Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n 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;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add min feerate checks - #1552

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee
Jul 13, 2022
Merged

Add min feerate checks#1552
TheBlueMatt merged 2 commits into
lightningdevkit:mainfrom
dunxen:2022-06-checkminrelayfee

Conversation

@dunxen

Copy link
Copy Markdown
Contributor

Fixes#1016

ariard
ariard previously approved these changes Jun 21, 2022

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dunxen
dunxen marked this pull request as ready for review June 21, 2022 06:06
Comment threadlightning/src/chain/package.rs Outdated
L::Target: Logger,
{
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
assert!(updated_feerate >= FEERATE_FLOOR_SATS_PER_KW as u64);

@tnulltnullJun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mh, do we really want to assert and panic here if something goes wrong?
Couldn't this just default to the floor, i.e., updated_feerate = max(updated_feerate, FEERATE_FLOOR_SATS_PER_KW)?

Just raising the question, but maybe panicking out is exactly what we want here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I get what you mean, but if we're getting strange feerates from our estimator then maybe we'd prefer to panic instead of silently defaulting? Although, I do think we need some sort of panic message at the least which is just an extra arg here. 🤷‍♂️

Would also be keen to know if this is what we normally want with these kinds of things in LDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I add the same thought if we should assert or panic. Not sure if we have yet consistent defensive programming recommendations.

@TheBlueMattTheBlueMatt left a comment

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 a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Cool, that sounds good. Happy to do this. Do we then just get rid of the trait comments about bothering with max()?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I think we should leave it on the trait, or at least mention that we'll always use at least 253.

@ariard

Copy link
Copy Markdown

I'm not a huge fan of asserting on these, I agree its nice to check the users' response, but if we're gonna add code around all the fee estimation fetches, we should just do the cmp::max ourself IMO.

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Personally, I would prefer if we still wrap that check around FeeEstimator, as I presume trait implementators might be lazy, belt-and-suspenders if cheap and straightforward are nice.

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

@ariard

Copy link
Copy Markdown

I'm not sure I undersood - are you agreeing that you'd rather see a wrapper of the FeeEstimator that does the max for us?

Yes, if that what you suggested as a could-be direction with your previous comment :) ?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Heh, yea, sorry, that wasn't clear, yes, I was suggesting we just wrap the trait in some helper that does the max.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 2 times, most recently from b992a6a to 5922330CompareJune 22, 2022 15:30
@codecov-commenter

codecov-commenter commented Jun 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1552 (fb0a015) into main (fda3819) will increase coverage by 0.19%.
The diff coverage is 100.00%.

❗ Current head fb0a015 differs from pull request most recent head 7bc6d0e. Consider uploading reports for the commit 7bc6d0e to get more accurate results

@@ Coverage Diff @@## main #1552 +/- ##
==========================================
+ Coverage 90.81% 91.01% +0.19% 
==========================================
Files 80 80 Lines 44534 45507 +973 Branches 44534 45507 +973 ==========================================
+ Hits 40445 41417 +972 - Misses 4089 4090 +1 
Impacted FilesCoverage Δ
lightning/src/chain/chaininterface.rs96.15% <100.00%> (+96.15%)⬆️
lightning/src/chain/channelmonitor.rs92.53% <100.00%> (+1.60%)⬆️
lightning/src/chain/onchaintx.rs94.90% <100.00%> (+0.92%)⬆️
lightning/src/chain/package.rs93.04% <100.00%> (ø)
lightning/src/ln/channel.rs88.75% <100.00%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs84.88% <100.00%> (-0.21%)⬇️
lightning/src/ln/functional_tests.rs96.96% <100.00%> (+0.13%)⬆️
lightning/src/ln/payment_tests.rs98.57% <0.00%> (-0.32%)⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda3819...7bc6d0e. Read the comment docs.

///
/// This method can be implemented with the following unit conversions:
/// * max(satoshis-per-byte * 250, 253)
/// * max(satoshis-per-kbyte / 4, 253)

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.

The unit conversions are still really useful.

F::Target: FeeEstimator,
{
pub(crate) fn new(fee_estimator: &'a F) -> Self
where

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.

You shoul dbe able to drop the where clause here - its redundant.


/// Wraps a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub(crate) struct LowerBoundedFeeEstimator<'a, F: Deref>(pub(crate) &'a F)

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.

Instead of storing a reference to a deref to a feeestimator and constructing the lowerboundedestimator whenever we need to get fees, lets just store the full deref to a feeestimator here, and then update places in the crate to store a LowerBoundedFeeEstimator, so its always that way and its a bit harder to forget to do the wrapping.

}
}

impl<F: Deref> FeeEstimator for LowerBoundedFeeEstimator<'_, F>

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.

Lets not bother with the trait and just implement directly, then in the codebase make things take a LowerBoundFeeEstimator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah, will make things simpler and then there's no forgetting to create a LowerBoundFeeEstimator as you mentioned :)

/// Minimum relay fee as required by bitcoin network mempool policy.
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
/// Minimum feerate that takes a sane approach to rounding
pub const FEERATE_FLOOR_SATS_PER_KW: u32 = 253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Minimum feerate that takes a sane approach to bitcoind weight-to-vbytes rounding"

I don't know if this subtlety is documented anywhere well, so feel free to ref Rusty's commit : ElementsProject/lightning@2e687b9

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch 3 times, most recently from 4093743 to 1956024CompareJune 29, 2022 14:22
/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).
///
/// This method can be implemented with the following unit conversions:
/// This wrapped method will be implemented with the following unit conversions:

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.

The point of listing the conversions is the user may need to convert from whatever unit their backend feerate API returns to the units here. Thus, its not that it "will" be implemented with the conversions, but that users "can" implement it using the listed conversions (but drop the max/253 bit) if they want.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, of course. I didn't even realise that was the main point of the comment here. I had just considered the max part. Will fix.

updates: &ChannelMonitorUpdate,
broadcaster: &B,
fee_estimator: &F,
fee_estimator: &LowerBoundedFeeEstimator<F>,

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.

This method is public - let's drop the wrapper from the parameter.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems we run into a few tricky issues here as we cannot clone a Deref to a FeeEstimator so that we can wrap it further down the line. Unless I'm missing something subtle and rusty. The main problem is we take in &F here and in some other places and we can't move out of the shared reference when we need to wrap.

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.

Uhhhh, right, uhhhh, uhhhh, so I think it'll work if we impl <D: Deref> FeeEstimator for D where D::Target: FeeEstimator. It doesn't currently break anything in test, dont think it'll break downstream stuff.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alright, let me go that direction and see :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Seems to do the trick!

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.

In general I think we need to go that way for all of our traits, but that's a rather large change and dealing with the bindings for it sounds....un-fun.


/// Wraps a `Deref` to a `FeeEstimator` so that any fee estimations provided by it
/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)

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 don't think we want this to be public at all - it should be pub(crate) instead, I think.

/// are bounded below by `FEERATE_FLOOR_SATS_PER_KW` (253 sats/KW)
pub struct LowerBoundedFeeEstimator<F: Deref>(pub F)
where
F::Target: FeeEstimator;

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.

nit: does this really need its own line?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Think rustfmt got me here 😅. Will fix.

@dunxen

Copy link
Copy Markdown
ContributorAuthor

Rebasing and directly modifying commits just this one last time before more review as a lot has changed from the previous revision.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 1956024 to 98ae8bfCompareJuly 4, 2022 19:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Let me know when you're ready for more review here.

@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from 7179109 to 9ec469fCompareJuly 8, 2022 06:00
///
/// This method can be implemented with the following unit conversions:
/// The following unit conversions can be used to convert to sats/KW. Note that it is not
/// necessary to use max() as the minimum of 253 will be enforced by LDK:

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.

nit: then why even mention the max?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

True story. Remove this and just leave in the max in the example conversion or also get rid of that?

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'd think just skip the max but leave the conversions.

Comment threadlightning/src/chain/onchaintx.rs Outdated
}
for (_, request) in bump_candidates.iter_mut() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &fee_estimator, &&*logger) {

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.

nit: you can drop the & on the fee_estimator entirely. Fewer &s good - we're already calling a fee estimator that is a reference to a reference to a reference :(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah seems like quite the onion 😅

Comment threadlightning/src/ln/channelmanager.rs Outdated
let mut should_persist = NotifyOption::SkipPersist;

let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let new_feerate = LowerBoundedFeeEstimator::new(&self.fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

Instead of peppering these everywhere, the ChannelManager::fee_estimator field should be a LowerBoundedFeeEstimator, then its very hard to screw up and forget to wrap.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm, ok so no need to worry about serialisation here? Field is completely ignored in public contract?

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.

The fee estimator itself? No, its not serialized, the user passes in a new fee estimator to the ChannelManager deserialize method.

Comment threadlightning/src/ln/channelmanager.rs Outdated
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&self.fee_estimator, &msg), channel_state, chan_entry);
let (closing_signed, tx) = try_chan_entry!(self, chan_entry.get_mut().closing_signed(&&self.fee_estimator, &msg), channel_state, chan_entry);

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.

You should be able to drop a & here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Hmm yeah I think I can now with how FeeEstimator currently looks.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So yeah we don't need it in this case, but if we make ChannelManager::fee_estimator a LowerBoundedFeeEstimator, then it seems necessary as we're working with something that's not a Deref to a FeeEstimator.

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.

Right, you'll need a single & here, which is a reference to a LowerBoundedFeeEstimator which holds a Deref to a FeeEstimator. Its still two references, but shouldn't need to touch this line of code, I belive?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the main issue here is that the signature expects &F for first argument and F: Deref where F::Target: FeeEstimator.

So it's a ref to a deref to a FeeEstimator, so that's a bit of a problem here :/
Errors with just a single & in the case where ChannelManager::fee_estimator is a LowerBoundedFeeEstimator, because of the signature.

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.

Right, but I thought we were moving to channel.rs only ever seeing LowerBoundedFeeEstimators, never a FeeEstimator itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, thought that was a public API but seems like Channel itself is not. So I can go ahead and adjust the signature.

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.

Ah! okay, wasn't sure what the confusion was. Thanks.

Comment threadlightning/src/ln/channel.rs Outdated
}

let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let feerate = LowerBoundedFeeEstimator::new(fee_estimator).get_est_sat_per_1000_weight(ConfirmationTarget::Normal);

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.

We don't need to wrap the estimator in channel.rs anymore, no? Plus a few places further down.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right!

@TheBlueMattTheBlueMatt left a comment

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.

LGTM. Feel free to squash and then let's land this!

Comment threadlightning/src/ln/channel.rs Outdated
if !self.is_outbound() {
if let Some(msg) = &self.pending_counterparty_closing_signed.take() {
return self.closing_signed(fee_estimator, &msg);
return self.closing_signed(&fee_estimator, &msg);

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.

You shouldnt need to touch this line now.

dunxen added 2 commits July 13, 2022 15:00
`LowerBoundedFeeEstimator` is a wrapper for `Deref`s to `FeeEstimator`s
that limits the get_est_sat_per_1000_weight() method to no less than 253
sats/kW.
@dunxen
dunxenforce-pushed the 2022-06-checkminrelayfee branch from fb0a015 to 7bc6d0eCompareJuly 13, 2022 13:05

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ACK 7bc6d0e

@TheBlueMatt
TheBlueMatt merged commit 2a3bf03 into lightningdevkit:mainJul 13, 2022
@dunxen
dunxen deleted the 2022-06-checkminrelayfee branch July 18, 2022 06:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add min_relay_fee checks for fee-estimation calls

5 participants

@dunxen@TheBlueMatt@ariard@codecov-commenter@tnull