Skip to content

Conversation

MPins
Copy link
Contributor

@MPins MPins commented Jul 10, 2025

This PR continues the work started in #7454 by @ziggie1984

The goal is to allow RPC callers to specify a custom sats_per_kweight value when crafting transactions, enabling finer control over fee rates. This is particularly useful for advanced channel management.

The lncli users will continue using the --sat_per_vbyte option, but fractions are now accepted (e.g., --sat_per_vbyte=1.08). Internally, the value will be converted to sat/kw when calling the RPC.

For the closechannel command, the --max_fee_rate option will also accept fractions and will likewise be converted to sat/kw internally when calling the RPC.

Original PR:

#7454

Happy to continue the discussion and iterate on this.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @MPins, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances fee rate control within the system by introducing a sats_per_kweight option for various on-chain and channel-related transactions. This change provides more granular control over transaction fees, which is particularly beneficial for advanced users managing Lightning channels. The update involves modifications to the command-line interface, RPC definitions, internal fee calculation logic, and comprehensive integration tests to ensure correctness and prevent conflicting fee specifications.

Highlights

  • New Fee Rate Option: Introduced a new --sat_per_kweight option across various lncli commands and walletrpc calls, allowing users to specify transaction fees in satoshis per kiloweight (sat/kweight). This provides finer control over fee rates, especially useful for advanced channel management.
  • API and Protocol Updates: Updated lnrpc/lightning.proto and lnrpc/walletrpc/walletkit.proto to include the new sat_per_kweight field, replacing the deprecated sat_per_byte field. Corresponding Swagger and generated Go files have been updated.
  • Fee Calculation Logic Enhancement: Modified the internal CalculateFeeRate utility to properly handle the new sat_per_kweight input, ensuring that only one fee rate type (sat_per_vbyte or sat_per_kweight) can be specified at a time. A security measure was also added to cap the effective fee rate at a default maximum.
  • Expanded Command Support: The --sat_per_kweight option is now available for lncli openchannel, batchopenchannel, sendcoins, sendmany, and closechannel commands, as well as walletrpc FundPsbt and BumpFee calls.
  • Integration Test Coverage: Added new integration tests to verify the correct application of sat_per_kweight for channel opening, sending coins, and sending to multiple addresses, including tests for mutual exclusivity with sat_per_vbyte.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@MPins MPins changed the title Kweight selection add sats_per_kweight option when crafting a transaction (continue) Jul 10, 2025
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a sats_per_kweight option for more granular fee control in various transaction-related commands. The changes are extensive, touching lncli commands, RPC definitions, and wallet logic. I've added several new integration tests to validate this new functionality.

My review focuses on ensuring consistency in argument validation across different commands, adherence to the style guide, and clarity in documentation and error messages. I've identified a few places where command-line argument validation can be improved and some documentation that could be more precise. Overall, the implementation is solid, and the new feature is a great addition.

Copy link
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

Left some initial comments

@MPins
Copy link
Contributor Author

MPins commented Aug 20, 2025

Left some initial comments

I’m doing a final double-check and plan to push the PR tomorrow.

@MPins MPins force-pushed the kweight-selection branch 2 times, most recently from 1bddccb to e23345b Compare August 23, 2025 18:30
@MPins MPins marked this pull request as ready for review August 23, 2025 18:45
@MPins MPins requested a review from ziggie1984 August 23, 2025 18:45
@MPins
Copy link
Contributor Author

MPins commented Aug 23, 2025

@ziggie1984 ready for review. Thanks!

@MPins
Copy link
Contributor Author

MPins commented Aug 26, 2025

Hello @saubyk could you please assign it to me.

Copy link
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

Looking good thank you for taking this PR over. I had some suggestions how to make this fractional feerate more user friendly on the lncli level.

@ziggie1984
Copy link
Collaborator

Regarding dropping the deprecated sat_per_byte option, can you create a release-note signaling the dropping of this feature for LND 20, so that we can drop the support in LND 21.0, this gives users time to change their setup, similar how we did it for the payment RPC endpoints.

@starius
Copy link
Collaborator

starius commented Aug 27, 2025

Thanks for working on this! This is very useful! I think about this feature every time I send a transaction and have to choose between 1 and 2 sats/vbyte.

I propose modifying lncli to accept fractional sats/vbyte and internally convert them into the proper sat_per_kw value (using SatPerKVByte.FeePerKWeight) before sending as sat_per_kw. This change would be backwards compatible: integer inputs (1, 2, 3, etc.) would result in the same values as before, while fractional inputs such as 1.2 or 1.05 would also be supported.

Note that 1 sat/vbyte = 250 sats/kw, so this modification does not introduce rounding errors for integer values.

This is an example of how it would work:

$ lncli sendcoins --sat_per_vbyte 1.2

@MPins
Copy link
Contributor Author

MPins commented Aug 27, 2025

Thanks for working on this! This is very useful! I think about this feature every time I send a transaction and have to choose between 1 and 2 sats/vbyte.

I propose modifying lncli to accept fractional sats/vbyte and internally convert them into the proper sat_per_kw value (using SatPerKVByte.FeePerKWeight) before sending as sat_per_kw. This change would be backwards compatible: integer inputs (1, 2, 3, etc.) would result in the same values as before, while fractional inputs such as 1.2 or 1.05 would also be supported.

Note that 1 sat/vbyte = 250 sats/kw, so this modification does not introduce rounding errors for integer values.

This is an example of how it would work:

$ lncli sendcoins --sat_per_vbyte 1.2

Good idea, thanks for your time!

@MPins
Copy link
Contributor Author

MPins commented Aug 27, 2025

Thanks for the review, @ziggie1984 and @starius . To summarize, I plan to:

  1. keep the deprecated field sat_per_byte and add a release-note signaling the dropping of this feature
  2. accept fractional sats/vbyte and convert the internally into the proper sat_per_kw
  3. address the other comments above

@ziggie1984
Copy link
Collaborator

Thanks for the review, @ziggie1984 and @starius . To summarize, I plan to:

That makes sense!

Release 20 should add the release-notes for removing the sat_per_byte option, and then we should open a PR dropping it for 21.

But this PR should definitely keep the sat_per_byte option.

@starius
Copy link
Collaborator

starius commented Aug 31, 2025

I have a couple of proposals.

  1. I propose to deprecate sat_per_vbyte field in this PR. New code should use sat_per_kw after the change is in a release.

  2. I propose to make a PR for https://github.com/lightninglabs/lndclient/ switching to new fields to make sure there are no problems in the new API. We could even test both PRs in our products. I volunteer to do the PR and to test it.

  3. If you remove sat_per_byte in the future, please make sure that an old client sending it would receive an error. The request shouldn't be interpreted as requesting zero fee-rate. Also it makes sense to provide code snippets in release notes illustrating how to do the transition.

@MPins
Copy link
Contributor Author

MPins commented Sep 1, 2025

I have a couple of proposals.

1. I propose to deprecate `sat_per_vbyte` field in this PR. New code should use `sat_per_kw` after the change is in a release.

That makes sense. If we go in that direction, we should also introduce a kweight-based field (perhaps MaxFeeRateKw) for MaxFeeRate in the closechannel RPC, and deprecate the current MaxFeeRate at the same time.

2. I propose to make a PR for https://github.com/lightninglabs/lndclient/ switching to new fields to make sure there are no problems in the new API. We could even test both PRs in our products. I volunteer to do the PR and to test it.

That would be great — I’d be more than happy to review your PR.

3. If you remove `sat_per_byte` in the future, please make sure that an old client sending it would receive an error. The request shouldn't be interpreted as requesting zero fee-rate. Also it makes sense to provide code snippets in release notes illustrating how to do the transition.

I will, thanks for the heads-up.

starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Include lightningnetwork/lnd#10067
add sats_per_kweight option when crafting a transaction (continue)
starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Use SatPerKw instead of SatPerVbyte in SendCoins, CloseChannel,
and walletrpc.BumpFee APIs.

Added new option WithSendCoinsFeerate for SendCoins and WithOpenChannelFeerate
for OpenChannel API specifying feerate in sats/kw.

Use new fields provded by lightningnetwork/lnd#10067
starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Use SatPerKw instead of SatPerVbyte in SendCoins, CloseChannel,
and walletrpc.BumpFee APIs.

Added new option WithSendCoinsFeerate for SendCoins and WithOpenChannelFeerate
for OpenChannel API specifying feerate in sats/kw.

Use new fields provided by lightningnetwork/lnd#10067
@starius
Copy link
Collaborator

starius commented Sep 1, 2025

2. I propose to make a PR for https://github.com/lightninglabs/lndclient/ switching to new fields to make sure there are no problems in the new API. We could even test both PRs in our products. I volunteer to do the PR and to test it.

That would be great — I’d be more than happy to review your PR.

I sent PR lightninglabs/lndclient#241 with updates for lndclient. It switches lnclient from SatPerVbyte to the new field.

starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Include lightningnetwork/lnd#10067
add sats_per_kweight option when crafting a transaction (continue)
starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Use SatPerKw instead of SatPerVbyte in SendCoins, CloseChannel,
and walletrpc.BumpFee APIs.

Added new option WithSendCoinsFeerate for SendCoins and WithOpenChannelFeerate
for OpenChannel API specifying feerate in sats/kw.

Use new fields provided by lightningnetwork/lnd#10067
starius added a commit to starius/lndclient that referenced this pull request Sep 1, 2025
Use SatPerKw instead of SatPerVbyte in SendCoins, CloseChannel,
and walletrpc.BumpFee APIs.

Added new option WithSendCoinsFeerate for SendCoins and WithOpenChannelFeerate
for OpenChannel API specifying feerate in sats/kw.

Use new fields provided by lightningnetwork/lnd#10067
@MPins MPins force-pushed the kweight-selection branch 9 times, most recently from 6f6b2e8 to ee4f39e Compare September 16, 2025 23:45
@MPins MPins requested a review from starius September 17, 2025 01:04
Comment on lines 76 to 79
// TODO: how to do it accurately using sat/kw?
require.Equal(
ht, int64(alicePendingUpdate.FeePerKw/250),
int64(bobFeeRate/250))
Copy link
Contributor Author

@MPins MPins Sep 17, 2025

Choose a reason for hiding this comment

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

Without this conversion back to sat/vB the CI is failing! (it is not failing locally). Any Idea is welcome!

--- FAIL: TestLightningNetworkDaemon (499.88s)
    harness_setup.go:25: Setting up HarnessTest...
    harness_setup.go:38: Prepare the miner and mine blocks to activate segwit...
    harness_setup.go:46: Connecting the miner at 127.0.0.1:10025 with the chain backend...
    --- FAIL: TestLightningNetworkDaemon/tranche11/240-of-317/btcd/rbf_coop_close (11.37s)
        harness_node.go:395: Starting node (name=Alice) with PID=16082
        harness_node.go:395: Starting node (name=Bob) with PID=16093
        lnd_coop_close_rbf_test.go:76: 
            	Error Trace:	/home/runner/work/lnd/lnd/itest/lnd_coop_close_rbf_test.go:76
            	            				/home/runner/work/lnd/lnd/lntest/harness.go:315
            	            				/home/runner/work/lnd/lnd/itest/lnd_test.go:130
            	Error:      	Not equal: 
            	            	expected: 2514
            	            	actual  : 2500
            	Test:       	TestLightningNetworkDaemon/tranche11/240-of-317/btcd/rbf_coop_close
        harness.go:393: finished test: rbf_coop_close, start height=723, end height=730, mined blocks=7
        harness.go:352: test failed, skipped cleanup
    lnd_test.go:138: Failure time: 2025-09-16 20:45:32.136
FAIL

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you also print the tx weight and absolute fee, please?
You can get the txid from the pending update, get the tx from the mempool, and then find its weight:

blockchain.GetTransactionWeight(btcutil.NewTx(tx))

The absolute fee can be found as the difference between the input amount and the sum of the outputs.
Then you can find the feerate using https://pkg.go.dev/github.com/lightningnetwork/lnd/lnwallet/chainfee#NewSatPerKWeight.
I propose finding and printing all three numbers to help debug this.

My theory is that this is a result of rounding up the absolute fee. The absolute fee is defined in satoshis. Even a single satoshi changes the feerate measured in sats/kw by multiple units (how many depends on the tx weight; e.g., for a weight of 800 wu, a single-satoshi difference in the absolute fee changes the feerate by 12.5 sats/kw).

We can verify this theory if we have all the numbers (weight, absolute fee, feerate).

Note that there was a change recently that affected fee calculation (rounding up instead of rounding down). Could this be responsible for the differences between your machine and CI?

Copy link
Contributor Author

@MPins MPins Sep 23, 2025

Choose a reason for hiding this comment

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

Just to let you know that I'm investigating further. Below the results I just got locally.

I added temporary logging to compute fee, weight and fee rate:

	// TODO: Check tx weight, absolute fee and fee rate to debug CI failure.
	var txid chainhash.Hash
	err = txid.SetBytes(alicePendingUpdate.Txid)
	// Transaction should be in mempool.
	require.NoError(ht, err)
	txmsg := ht.AssertTxInMempool(txid)
	tx := btcutil.NewTx(txmsg)
	sumOfOutput := int64(0)
	for _, txOut := range tx.MsgTx().TxOut {
		sumOfOutput += txOut.Value
	}
	parentHash := tx.MsgTx().TxIn[0].PreviousOutPoint.Hash	
	// Parent transaction should be confirmed.
	rawTx := ht.Miner().GetRawTransaction(parentHash)
	parent := rawTx.MsgTx()
	inValue := parent.TxOut[tx.MsgTx().TxIn[0].PreviousOutPoint.Index].Value
	log.Printf("Pending close tx fee: %d", inValue-sumOfOutput)

	// Weight should be around 724 vbytes.
	txWeight := blockchain.GetTransactionWeight(tx)
	log.Printf("Pending close tx weight: %d", txWeight)

	endingFeeRate := chainfee.SatPerKWeight(
		(inValue - sumOfOutput) * 1000 / txWeight,
	)
	log.Printf("Pending close tx fee rate: %d sat/kw", endingFeeRate)

	log.Printf("Alice pending update close fee rate: %d sat/kw",
		alicePendingUpdate.FeePerKw,
	)

	log.Printf("Bob close fee rate: %d sat/kw", bobFeeRate)

And locally sometimes the test PASS:

pins-dev@framework:~/Projects/lnd$ make itest icase=rbf_coop_close
 Building itest btcd and lnd.
CGO_ENABLED=0 go build -v -tags="integration" -o itest/btcd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=sqldb/v1.0.10-820-gee4f39e2c-dirty" github.com/btcsuite/btcd
CGO_ENABLED=0 go build -v -tags="dev autopilotrpc chainrpc invoicesrpc neutrinorpc peersrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc integration btcd"  -o itest/lnd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=sqldb/v1.0.10-820-gee4f39e2c-dirty" github.com/lightningnetwork/lnd/cmd/lnd
 Building itest binary for btcd backend.
CGO_ENABLED=0 go test -v ./itest -tags="dev autopilotrpc chainrpc invoicesrpc neutrinorpc peersrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc integration btcd" -c -o itest/itest.test
rm -rf itest/*.log itest/.logs-*
 Running integration tests with btcd backend.
date
Tue Sep 23 11:44:17 AM PDT 2025
EXEC_SUFFIX= scripts/itest_part.sh 0 1 0 -test.run="TestLightningNetworkDaemon/tranche.*/.*-of-.*/.*/rbf_coop_close" -test.timeout=180m  -test.v
/home/pins-dev/Projects/lnd/itest/itest.test -test.run=TestLightningNetworkDaemon/tranche.*/.*-of-.*/.*/rbf_coop_close -test.timeout=180m -test.v -logoutput -logdir=.logs-tranche0 -lndexec=/home/pins-dev/Projects/lnd/itest/lnd-itest -btcdexec=/home/pins-dev/Projects/lnd/itest/btcd-itest -splittranches=1 -runtranche=0 -shuffleseed=0
=== RUN   TestLightningNetworkDaemon
    harness_setup.go:25: Setting up HarnessTest...
    harness_setup.go:38: Prepare the miner and mine blocks to activate segwit...
    harness_setup.go:46: Connecting the miner at 127.0.0.1:10209 with the chain backend...
=== RUN   TestLightningNetworkDaemon/tranche00/181-of-317/btcd/rbf_coop_close
    harness_node.go:395: Starting node (name=Alice) with PID=208793
    harness_node.go:395: Starting node (name=Bob) with PID=208816
2025/09/23 11:44:29 Pending close tx fee: 1930
2025/09/23 11:44:29 Pending close tx weight: 770
2025/09/23 11:44:29 Pending close tx fee rate: 2506 sat/kw
2025/09/23 11:44:29 Alice pending update close fee rate: 2500 sat/kw
2025/09/23 11:44:29 Bob close fee rate: 2500 sat/kw
    harness.go:1331: Test: rbf_coop_close, close channel got error: received err from close channel stream: rpc error: code = Unknown desc = cannot pay for fee of 0.00077200 BTC, only have 0.00049817 BTC local balance
    harness.go:393: finished test: rbf_coop_close, start height=438, end height=446, mined blocks=8
=== RUN   TestLightningNetworkDaemon/tranche00/182-of-317/btcd/rbf_coop_close_disconnect
    harness_node.go:395: Starting node (name=Alice) with PID=208923
    harness_node.go:395: Starting node (name=Bob) with PID=208949
    harness.go:393: finished test: rbf_coop_close_disconnect, start height=446, end height=453, mined blocks=7
=========> tranche 0 finished, tested 317 cases, mined blocks: 8
--- PASS: TestLightningNetworkDaemon (26.56s)
    --- PASS: TestLightningNetworkDaemon/tranche00/181-of-317/btcd/rbf_coop_close (13.53s)
    --- PASS: TestLightningNetworkDaemon/tranche00/182-of-317/btcd/rbf_coop_close_disconnect (11.76s)
PASS

Sometimes it FAIL:

pins-dev@framework:~/Projects/lnd$ make itest icase=rbf_coop_close
 Building itest btcd and lnd.
CGO_ENABLED=0 go build -v -tags="integration" -o itest/btcd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=sqldb/v1.0.10-820-gee4f39e2c-dirty" github.com/btcsuite/btcd
CGO_ENABLED=0 go build -v -tags="dev autopilotrpc chainrpc invoicesrpc neutrinorpc peersrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc integration btcd"  -o itest/lnd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=sqldb/v1.0.10-820-gee4f39e2c-dirty" github.com/lightningnetwork/lnd/cmd/lnd
 Building itest binary for btcd backend.
CGO_ENABLED=0 go test -v ./itest -tags="dev autopilotrpc chainrpc invoicesrpc neutrinorpc peersrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc integration btcd" -c -o itest/itest.test
rm -rf itest/*.log itest/.logs-*
 Running integration tests with btcd backend.
date
Tue Sep 23 11:43:42 AM PDT 2025
EXEC_SUFFIX= scripts/itest_part.sh 0 1 0 -test.run="TestLightningNetworkDaemon/tranche.*/.*-of-.*/.*/rbf_coop_close" -test.timeout=180m  -test.v
/home/pins-dev/Projects/lnd/itest/itest.test -test.run=TestLightningNetworkDaemon/tranche.*/.*-of-.*/.*/rbf_coop_close -test.timeout=180m -test.v -logoutput -logdir=.logs-tranche0 -lndexec=/home/pins-dev/Projects/lnd/itest/lnd-itest -btcdexec=/home/pins-dev/Projects/lnd/itest/btcd-itest -splittranches=1 -runtranche=0 -shuffleseed=0
=== RUN   TestLightningNetworkDaemon
    harness_setup.go:25: Setting up HarnessTest...
    harness_setup.go:38: Prepare the miner and mine blocks to activate segwit...
    harness_setup.go:46: Connecting the miner at 127.0.0.1:10196 with the chain backend...
=== RUN   TestLightningNetworkDaemon/tranche00/181-of-317/btcd/rbf_coop_close
    harness_node.go:395: Starting node (name=Alice) with PID=207944
    harness_node.go:395: Starting node (name=Bob) with PID=207981
2025/09/23 11:43:54 Pending close tx fee: 1930
2025/09/23 11:43:54 Pending close tx weight: 767
2025/09/23 11:43:54 Pending close tx fee rate: 2516 sat/kw
2025/09/23 11:43:54 Alice pending update close fee rate: 2514 sat/kw
2025/09/23 11:43:54 Bob close fee rate: 2500 sat/kw
    lnd_coop_close_rbf_test.go:115: 
                Error Trace:    /home/pins-dev/Projects/lnd/itest/lnd_coop_close_rbf_test.go:115
                                                        /home/pins-dev/Projects/lnd/lntest/harness.go:315
                                                        /home/pins-dev/Projects/lnd/itest/lnd_test.go:130
                Error:          Not equal: 
                                expected: 2514
                                actual  : 2500
                Test:           TestLightningNetworkDaemon/tranche00/181-of-317/btcd/rbf_coop_close
    harness.go:393: finished test: rbf_coop_close, start height=438, end height=445, mined blocks=7
    harness.go:352: test failed, skipped cleanup
=== NAME  TestLightningNetworkDaemon
    lnd_test.go:138: Failure time: 2025-09-23 11:43:55.160
=========> tranche 0 finished, tested 317 cases, mined blocks: 0
--- FAIL: TestLightningNetworkDaemon (13.06s)
    --- FAIL: TestLightningNetworkDaemon/tranche00/181-of-317/btcd/rbf_coop_close (11.80s)
FAIL
make: *** [Makefile:224: itest-only] Error 255

Copy link
Contributor Author

@MPins MPins Sep 25, 2025

Choose a reason for hiding this comment

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

It’s not an error—the fee rate calculation may differ due to weight estimation versus the actual transaction weight. To make the test work properly, I’m using InDelta.

Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe normally here P2TR addresses should be used and they have an exact estimate imo ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is the transactions that close the channel. To use P2TR we should change the test to use simple taproot channels. IMO we should not change the test that much.

@MPins
Copy link
Contributor Author

MPins commented Sep 17, 2025

Hello @starius and @ziggie1984 ready for another review!

@MPins
Copy link
Contributor Author

MPins commented Sep 25, 2025

Hello @starius and @ziggie1984 ready for another review! Thanks!

Copy link
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

Looking good 👍 had some comments.

// A manual fee rate set in sat/vbyte that should be used when crafting the
// transaction.
uint64 sat_per_vbyte = 4;
uint64 sat_per_vbyte = 4 [deprecated = true];
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am really not sure if we should deprecate the sat_per_vbyte option, I don't think we should do it, if users still want to use sat_per_vbyte its still a standard option.

Copy link
Contributor Author

@MPins MPins Sep 30, 2025

Choose a reason for hiding this comment

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

@starius suggested the deprecation and I agreed with him. The regular users will be using sat_per_vbyte through lncli commands, the deprecated field will affect only the RPC interface.

"SatPerVByte should be set, but not both")
// Only one fee field may be set: satPerKWeight, satPerByte, or
// satPerVByte.
if (satPerKWeight != 0 && (satPerByte != 0 || satPerVByte != 0)) ||
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe something more readable:

	// Only one fee field may be set: satPerKWeight, satPerByte, or
	// satPerVByte. Set the fee rate based on which field is provided.
	var satPerKw chainfee.SatPerKWeight
	fieldsSet := 0

	if satPerVByte != 0 {
		satPerKw = chainfee.SatPerKVByte(satPerVByte * 1000).FeePerKWeight()
		fieldsSet++
	}
	if satPerByte != 0 {
		satPerKw = chainfee.SatPerKVByte(satPerByte * 1000).FeePerKWeight()
		fieldsSet++
	}
	if satPerKWeight != 0 {
		satPerKw = chainfee.SatPerKWeight(satPerKWeight)
		fieldsSet++
	}

	if fieldsSet > 1 {
		return feeRate, fmt.Errorf("only one fee field may " +
			"be set")
	}

Copy link
Collaborator

Choose a reason for hiding this comment

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

moreover since we use sat_per_byte in the same way that sat_per_vbyte I wonder if we should drop the support completely because it is not accurate ? @starius


// parseFeeRate converts fee from sat/vB to sat/kw using fixed-point
// math to avoid rounding errors from floating-point arithmetic.
func parseFeeRate(ctx *cli.Context, flagName string) (uint64, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why do we introduce a new lib here ? given that float64 have a precision of 15 bits, we should just use the built in method of parsing float, since we do later on just grep the integer part of the number anyways ?

Copy link
Contributor Author

@MPins MPins Sep 29, 2025

Choose a reason for hiding this comment

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

@starius proposed using decimal to avoid rounding errors with float arithmetic.

I hadn’t considered the weight of adding a new dependency — to avoid that, we might keep the float64 arithmetic with explicit rounding up.

What you both think about it?

the pathfinder should use when finding a route.

### ⚠️ **Warning:** The deprecated fee rate option --sat_per_byte will be removed in release version **0.21**

Copy link
Collaborator

Choose a reason for hiding this comment

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

now needs to be 0.22 since this PR will only be part of 21

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok. I'll wait the final decision about deprecated field to change it.

If there is any chance to review the inclusion of this PR in the 0.20!?

If we include the changes to the FeePerKwFloor and AbsoluteFeePerKwFloor we would allow the users to craft transactions below 1 sat/vb. Imo would be the perfect timming.

const (
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
// estimating transaction fees before signing.
FeePerKwFloor SatPerKWeight = 253
// AbsoluteFeePerKwFloor is the lowest fee rate in sat/kw of a
// transaction that we should ever _create_. This is the equivalent
// of 1 sat/byte in sat/kw.
AbsoluteFeePerKwFloor SatPerKWeight = 250
)

require.Equal(ht, alicePendingUpdate.FeePerVbyte, int64(bobFeeRate))
// Using InDelta as fee rate calc might differ due to weight estimation
// versuns actual tx weight.
require.InDelta(
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we using non-P2TR addresses here in the test tho ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally we should keep the changes to the test as minimal as possible. That's why I'm using InDelta.

require.NotNil(ht, aliceCloseUpdate)
require.Equal(ht, alicePendingUpdate.FeePerVbyte, int64(bobFeeRate))
// Using InDelta as fee rate calc might differ due to weight estimation
// versuns actual tx weight.
Copy link
Collaborator

Choose a reason for hiding this comment

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

versuns => versus ?

Comment on lines 76 to 79
// TODO: how to do it accurately using sat/kw?
require.Equal(
ht, int64(alicePendingUpdate.FeePerKw/250),
int64(bobFeeRate/250))
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe normally here P2TR addresses should be used and they have an exact estimate imo ?

@MPins MPins changed the title add sats_per_kweight option when crafting a transaction (continue) Add fractional sat/vB support (lncli) and sats_per_kw (RPC) when crafting a tx Sep 27, 2025
@MPins MPins changed the title Add fractional sat/vB support (lncli) and sats_per_kw (RPC) when crafting a tx Fees: add fractional sat/vB support (lncli) and sats_per_kw (RPC) Sep 27, 2025
@MPins MPins force-pushed the kweight-selection branch from c5dc41b to b5852ad Compare October 1, 2025 17:13
MPins and others added 8 commits October 1, 2025 10:20
For EstimateFeeResponse, SendManyRequest, SendCoinsRequest,
CloseChannelRequest, BatchOpenChannelRequest, OpenChannelRequest,
PendingSweeps, BumpFeeRequest the sat_per_kw field is added.

This allows more fine granular control of transaction fees.
Fee calculation for sendcoins, sendmany, openchannel,
closechannel, PendingSweeps, BumpFee has now the option
sat_per_kw.

In addition a safety check is added to prevent very high fees.

For the estimatefee cmd the fee in sat_per_kw is added
to the response.
The sat_per_vbyte input option now accepts fractional values and is
internally converted into sat_per_kw.

The max_fee_per_vbyte input option now accepts fractional values and is
internally converted into max_fee_per_kw for fee calculation.

Add the sat_per_kw option for the lnrpc cmds
sendcoins, sendmany, openchannel, batchopenchannel, closechannel
and closeallchannels.

Add the sat_per_kw for estimatefee in the response.

Add sat_per_kw option for walletrpc cmds "wallet bumpfee" and
in the response of "wallet pending sweeps".

Add max_fee_per_kw for closechannel command.
Add new itests for openchannel, sendcoins and  sendmany.
Fix the test "rbf coop close" that was broken by
a safety check added to prevent very high fees.
@MPins MPins force-pushed the kweight-selection branch from b5852ad to aa73d97 Compare October 1, 2025 17:22
@MPins
Copy link
Contributor Author

MPins commented Oct 1, 2025

@ziggie1984 thanks for the review. I've addressed the comments.

Let's wait the @starius on deprecated related comments to address them.

@MPins MPins requested a review from ziggie1984 October 1, 2025 18:34
Sign up for free to 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.

3 participants