-
Notifications
You must be signed in to change notification settings - Fork 421
Put a 10_000vByte cap on HolderHTLCOutput
0FC package templates
#4129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Put a 10_000vByte cap on HolderHTLCOutput
0FC package templates
#4129
Conversation
👋 Thanks for assigning @TheBlueMatt as a reviewer! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4129 +/- ##
==========================================
+ Coverage 88.63% 88.76% +0.13%
==========================================
Files 180 180
Lines 134878 135660 +782
Branches 134878 135660 +782
==========================================
+ Hits 119543 120425 +882
+ Misses 12567 12467 -100
Partials 2768 2768
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
lightning/src/chain/package.rs
Outdated
// See rust-bitcoin to_vbytes_ceil | ||
let self_vbytes = (self.weight() + 3) / 4; // This is the weight of the witnesses alone, we need to add more here | ||
let other_vbytes = (other.weight() + 3) / 4; | ||
// What is a good offset to use here to leave room for the user-provided input-output pair? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmmmmmmmm, I wonder if we shouldn't just not merge and then do the work in the events::bump_transaction
module and add like a needs_v3_transaction: Option<()>
in the event? That way its at least pretty explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean aggregate in bump_transaction
? How about restrict ourselves to aggregate max 25 HTLCs ? This should be good for any conceivable user-provided input-output pair.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No as in break an aggregation in bump_transaction
63e8f1c
to
db273bb
Compare
db273bb
to
107eb25
Compare
🔔 1st Reminder Hey @TheBlueMatt! This PR has been waiting for your review. |
// Cap the size of transactions claiming `HolderHTLCOutput` in 0FC channels. | ||
// Otherwise, we could hit the max 10_000vB size limit on V3 transactions | ||
// (BIP 431 rule 4). | ||
25 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is okay, but I thought the point of pulling this out into the bump_transaction
logic is so that we could do the split after we see the inputs the user wants to contribute so that we can get close to 10k without exceeding it, rather than picking some random "max overhead" constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks yea let me know the commit below sounds
Otherwise, we could hit the max 10_000vB size limit on V3 transactions (BIP 431 rule 4).
107eb25
to
c222c41
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
approach lgtm
// This matches the scheme used in `onchaintx.rs`, so for non-0fc-channels, | ||
// this should match the `ClaimId` of the claim generated in `onchaintx.rs`. | ||
let mut engine = Sha256::engine(); | ||
for htlc in htlcs { | ||
engine.input(&htlc.commitment_txid.to_byte_array()); | ||
engine.input(&htlc.htlc.transaction_output_index.unwrap().to_be_bytes()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: pull out into ClaimID::from_prev_outs
to de-duplicate?
let unsigned_tx_weight = | ||
htlc_tx.weight().to_wu() - (htlc_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT); | ||
let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight; | ||
if expected_signed_tx_weight >= max_weight { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this just be >? We're allowed to be on exactly 10,000 vbytes, just no larger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered this, but went for the more conservative approach here.
let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight; | ||
if expected_signed_tx_weight >= max_weight { | ||
let extra_weight = expected_signed_tx_weight - max_weight; | ||
let htlcs_to_remove = (extra_weight / chan_utils::htlc_timeout_tx_weight(channel_type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not critical, but I think these weights include transaction overhead (version etc) so we'll overcount by 40 wu per htlc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, we should just use the weight of the HTLC input-output pair
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks ! yes this likely resolves the weird + 2 I've got below
let _node_a_id = nodes[0].node.get_our_node_id(); | ||
let _node_b_id = nodes[1].node.get_our_node_id(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: unused vars unnecessary?
if expected_signed_tx_weight >= max_weight { | ||
let extra_weight = expected_signed_tx_weight - max_weight; | ||
let htlcs_to_remove = (extra_weight / chan_utils::htlc_timeout_tx_weight(channel_type) | ||
// If we remove extra_weight / timeout_weight + 1 we sometimes still land above max_weight |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this wouldn't be an issue if we just round up the integer division?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likely it's because htlc_timeout_tx_weight
is the weight of the full-transaction, but we want to only count the bytes from the single input-output pair
// (BIP 431 rule 4). | ||
chan_utils::TRUC_MAX_WEIGHT | ||
} else { | ||
u64::MAX |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well cap this to the max weight we can relay?
engine.input(&htlc.commitment_txid.to_byte_array()); | ||
engine.input(&htlc.htlc.transaction_output_index.unwrap().to_be_bytes()); | ||
} | ||
let utxo_id = ClaimId(Sha256::from_engine(engine).to_byte_array()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't we want to reuse the same ID until we move on to the next batch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, was just wondering this - should we use the one from the event at least until we split the batch, which would work in the common case. Might want to sort the outputs so that we use them in a deterministic order (I imagine they are in the event, but...)
}); | ||
htlc_tx.input.push(htlc_input); | ||
let htlc_output = htlc_descriptor.tx_output(&self.secp); | ||
htlc_tx.output.push(htlc_output); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to break out of this loop early if we get close to the max_weight
? Would mean generating the claim ID during this loop rather than separately but that's trivial. Would avoid an extra coin-selection pass in a few cases, but its not critical.
Otherwise, we could potentially hit the max 10_000vB size limit on V3 transactions (BIP 431 rule 4) if we aggregate enough HTLC-claims together.