Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Integrate BumpTransactionEventHandler into existing anchor tests by wpaulino · Pull Request #2403 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
9 changes: 9 additions & 0 deletions lightning/src/chain/chaininterface.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,9 +14,18 @@
//! disconnections, transaction broadcasting, and feerate information requests.

use core::{cmp, ops::Deref};
use core::convert::TryInto;

use bitcoin::blockdata::transaction::Transaction;

// TODO: Define typed abstraction over feerates to handle their conversions.
Comment thread
tnull marked this conversation as resolved.
pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
(fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
}
pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
Comment thread
wpaulino marked this conversation as resolved.
}

/// An interface to send a transaction to the Bitcoin network.
pub trait BroadcasterInterface {
/// Sends a list of transactions out to (hopefully) be mined.
Expand Down
24 changes: 20 additions & 4 deletions lightning/src/chain/onchaintx.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1;

use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
use crate::ln::msgs::DecodeError;
use crate::ln::PaymentPreimage;
Expand DownExpand Up@@ -623,19 +624,31 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
return inputs.find_map(|input| match input {
// Commitment inputs with anchors support are the only untractable inputs supported
// thus far that require external funding.
PackageSolvingData::HolderFundingOutput(..) => {
PackageSolvingData::HolderFundingOutput(output) => {
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
"Holder commitment transaction mismatch");

let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
if let Some(input_amount_sat) = output.funding_amount {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we should keep yielding commitment transaction even if they meet the sufficient feerate. A commitment transaction attached with a ConfirmationTarget::HighPriority can be a hint you’re under pinning attacks or even that your transaction-relay eclipsed.

This information could be consumed by an anomalie detection module (Eclair has one for block-relay though I don’t know a Lightning implem which has one for transaction-relay, as it has been discussed in the past).

I would rather handle it back to the user and instead extend our documentation, or what do you think ? Is yielding a lot of ChannelClose raising issues in term of higher-level API ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how generating the events helps with that, though - we could have the same issue with anchors or non-anchors, and if you want to detect it you can do it at the transaction-broadcaster level. Most likely, the user has the events hooked into the BumpTransactionEventHandler anyway, which doesn't have any such handling and we're back to square one.

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the following comment can be added above ChannelClose (alternatively a earliest_cltv_expiry can be added in ChannelClose generation in ChannelMonitor::get_repeated_events though won’t be used for now).

diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs
index cbd5becd..097e868b 100644
--- a/lightning/src/events/bump_transaction.rs
+++ b/lightning/src/events/bump_transaction.rs
@@ -262,6 +262,12 @@ pub enum BumpTransactionEvent {
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
/// be not urgent.
+ /// + /// Note if the commitment transaction has pending HTLC outputs that we can satisfies with valid
+ /// witnesses, the module responsible for broadcast should be ready to take corrective actions
+ /// if the local mempool is partitioned, or full-node transaction-relay capabilities tampered
+ /// by an eclipse attack. Those corrective actions should be take on the earliest `cltv_expiry`
+ /// of the set of pending htlcs.
///
/// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
/// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input

If we want some kind of big warning that something isn't confirming when we expected it to, it needs to be a separate piece of logic that handles both anchor and non-anchor channels and exists independently.

Yeah I thought above that type of automatic anomalie detection logic in the past, see bitcoin/bitcoin#18987. Good if we start to document or indicate where can be the hooks points on our side, as probably you won’t have the same logic for mobile clients vs servers (or at the very least not the same reaction policy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this isn't specific to anchor, and I don't see how its related to this PR. If you want to add a similar comment to the broadcaster (or, better, a much longer-form discussion of risks of transaction relay and the lightning security model relying on it) that would be very welcome, but I'm not sure why it has to be on the anchor-specific bumper?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I'm not sure why it has to be on the anchor-specific bumper?

The anomalie detection module should be based on the frequency of the anchor-specific bumper, as the “ideal" frequency should be the one of a confirmation in normal mempols propagation and the anomalie detection works compared from discrepancies of its “ideal”, so yeah to me changing the ChannelClose announcement is a loss of relevant information.

All that said, we can move it elsewhere, let’s not invalidate the review so far.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It doesn't matter how many times we bump, we only get useful information once per block, so if you're trying to figure out if a transaction isn't getting confirmed, you only need to look once per block, since that's the only time your transaction can get confirmed :)

Comment thread
wpaulino marked this conversation as resolved.
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
if compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64) >=
package_target_feerate_sat_per_1000_weight
{
log_debug!(logger, "Commitment transaction {} already meets required feerate {} sat/kW",
Comment thread
wpaulino marked this conversation as resolved.
tx.txid(), package_target_feerate_sat_per_1000_weight);
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
Comment thread
wpaulino marked this conversation as resolved.
}
}

// We'll locate an anchor output we can spend within the commitment transaction.
let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
match chan_utils::get_anchor_output(&tx, funding_pubkey) {
// An anchor output was found, so we should yield a funding event externally.
Some((idx, _)) => {
// TODO: Use a lower confirmation target when both our and the
// counterparty's latest commitment don't have any HTLCs present.
let conf_target = ConfirmationTarget::HighPriority;
let package_target_feerate_sat_per_1000_weight = cached_request
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
Some((
new_timer,
package_target_feerate_sat_per_1000_weight as u64,
Expand DownExpand Up@@ -739,6 +752,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
// Once a pending claim has an id assigned, it remains fixed until the claim is
// satisfied, regardless of whether the claim switches between different variants of
// `OnchainClaim`.
let claim_id = match claim {
OnchainClaim::Tx(tx) => {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/chain/package.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -429,7 +429,7 @@ impl Readable for HolderHTLCOutput {
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
funding_amount: Option<u64>,
pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}

Expand Down
Loading