Skip to content

Commit 093fb0d

Browse files
committed
rpcserver+peer+chancloser: change rbf coop close from sat/vb to sat/kw
Change rbf coop close flow to use sat/kw insted of sat/vb, and update the unit tests accordingly.
1 parent db91215 commit 093fb0d

File tree

5 files changed

+37
-31
lines changed

5 files changed

+37
-31
lines changed

lnwallet/chancloser/rbf_coop_states.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ type SendShutdown struct {
100100

101101
// IdealFeeRate is the ideal fee rate we'd like to use for the closing
102102
// attempt.
103-
IdealFeeRate chainfee.SatPerVByte
103+
IdealFeeRate chainfee.SatPerKWeight
104104
}
105105

106106
// protocolSealed indicates that this struct is a ProtocolEvent instance.
@@ -182,7 +182,7 @@ func (c *ChannelFlushed) protocolSealed() {}
182182
// - toState: LocalOfferSent
183183
type SendOfferEvent struct {
184184
// TargetFeeRate is the fee rate we'll use for the closing transaction.
185-
TargetFeeRate chainfee.SatPerVByte
185+
TargetFeeRate chainfee.SatPerKWeight
186186
}
187187

188188
// protocolSealed indicates that this struct is a ProtocolEvent instance.
@@ -304,7 +304,7 @@ type Environment struct {
304304
// DefaultFeeRate is the fee we'll use for the closing transaction if
305305
// the user didn't specify an ideal fee rate. This may happen if the
306306
// remote party is the one that initiates the co-op close.
307-
DefaultFeeRate chainfee.SatPerVByte
307+
DefaultFeeRate chainfee.SatPerKWeight
308308

309309
// ThawHeight is the height at which the channel will be thawed. If
310310
// this is None, then co-op close can occur at any moment.
@@ -453,7 +453,7 @@ type ShutdownPending struct {
453453

454454
// IdealFeeRate is the ideal fee rate we'd like to use for the closing
455455
// attempt.
456-
IdealFeeRate fn.Option[chainfee.SatPerVByte]
456+
IdealFeeRate fn.Option[chainfee.SatPerKWeight]
457457

458458
// EarlyRemoteOffer is the offer we received from the remote party
459459
// before we received their shutdown message. We'll stash it to process
@@ -498,7 +498,7 @@ type ChannelFlushing struct {
498498
// IdealFeeRate is the ideal fee rate we'd like to use for the closing
499499
// transaction. Once the channel has been flushed, we'll use this as
500500
// our target fee rate.
501-
IdealFeeRate fn.Option[chainfee.SatPerVByte]
501+
IdealFeeRate fn.Option[chainfee.SatPerKWeight]
502502
}
503503

504504
// String returns the name of the state for ChannelFlushing.
@@ -732,7 +732,7 @@ type LocalOfferSent struct {
732732
ProposedFee btcutil.Amount
733733

734734
// ProposedFeeRate is the fee rate we proposed to the remote party.
735-
ProposedFeeRate chainfee.SatPerVByte
735+
ProposedFeeRate chainfee.SatPerKWeight
736736

737737
// LocalSig is the signature we sent to the remote party.
738738
LocalSig lnwire.Sig
@@ -781,7 +781,7 @@ type ClosePending struct {
781781
*CloseChannelTerms
782782

783783
// FeeRate is the fee rate of the closing transaction.
784-
FeeRate chainfee.SatPerVByte
784+
FeeRate chainfee.SatPerKWeight
785785

786786
// Party indicates which party is at this state. This is used to
787787
// implement the state transition properly, based on ShouldRouteTo.

lnwallet/chancloser/rbf_coop_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ func newRbfCloserTestHarness(t *testing.T,
783783
ChanPoint: chanPoint,
784784
ChanID: chanID,
785785
Scid: scid,
786-
DefaultFeeRate: defaultFeeRate.FeePerVByte(),
786+
DefaultFeeRate: defaultFeeRate,
787787
ThawHeight: cfg.thawHeight,
788788
RemoteUpfrontShutdown: cfg.remoteUpfrontAddr,
789789
LocalUpfrontShutdown: cfg.localUpfrontAddr,
@@ -854,7 +854,7 @@ func TestRbfChannelActiveTransitions(t *testing.T) {
854854
localAddr := lnwire.DeliveryAddress(bytes.Repeat([]byte{0x01}, 20))
855855
remoteAddr := lnwire.DeliveryAddress(bytes.Repeat([]byte{0x02}, 20))
856856

857-
feeRate := chainfee.SatPerVByte(1000)
857+
feeRate := chainfee.SatPerKWeight(250_000)
858858

859859
// Test that if a spend event is received, the FSM transitions to the
860860
// CloseFin terminal state.
@@ -1050,7 +1050,7 @@ func TestRbfShutdownPendingTransitions(t *testing.T) {
10501050
t.Run("initiator_shutdown_recv_ok", func(t *testing.T) {
10511051
firstState := *startingState
10521052
firstState.IdealFeeRate = fn.Some(
1053-
chainfee.FeePerKwFloor.FeePerVByte(),
1053+
chainfee.FeePerKwFloor,
10541054
)
10551055
firstState.ShutdownScripts = ShutdownScripts{
10561056
LocalDeliveryScript: localAddr,
@@ -1097,7 +1097,7 @@ func TestRbfShutdownPendingTransitions(t *testing.T) {
10971097
t.Run("responder_complete", func(t *testing.T) {
10981098
firstState := *startingState
10991099
firstState.IdealFeeRate = fn.Some(
1100-
chainfee.FeePerKwFloor.FeePerVByte(),
1100+
chainfee.FeePerKwFloor,
11011101
)
11021102
firstState.ShutdownScripts = ShutdownScripts{
11031103
LocalDeliveryScript: localAddr,
@@ -1128,7 +1128,7 @@ func TestRbfShutdownPendingTransitions(t *testing.T) {
11281128
t.Run("early_remote_offer_shutdown_complete", func(t *testing.T) {
11291129
firstState := *startingState
11301130
firstState.IdealFeeRate = fn.Some(
1131-
chainfee.FeePerKwFloor.FeePerVByte(),
1131+
chainfee.FeePerKwFloor,
11321132
)
11331133
firstState.ShutdownScripts = ShutdownScripts{
11341134
LocalDeliveryScript: localAddr,
@@ -1175,7 +1175,7 @@ func TestRbfShutdownPendingTransitions(t *testing.T) {
11751175
t.Run("early_remote_offer_shutdown_received", func(t *testing.T) {
11761176
firstState := *startingState
11771177
firstState.IdealFeeRate = fn.Some(
1178-
chainfee.FeePerKwFloor.FeePerVByte(),
1178+
chainfee.FeePerKwFloor,
11791179
)
11801180
firstState.ShutdownScripts = ShutdownScripts{
11811181
LocalDeliveryScript: localAddr,
@@ -1433,7 +1433,7 @@ func TestRbfCloseClosingNegotiationLocal(t *testing.T) {
14331433
}
14341434

14351435
sendOfferEvent := &SendOfferEvent{
1436-
TargetFeeRate: chainfee.FeePerKwFloor.FeePerVByte(),
1436+
TargetFeeRate: chainfee.FeePerKwFloor,
14371437
}
14381438

14391439
balanceAfterClose := localBalance.ToSatoshis() - absoluteFee
@@ -1614,7 +1614,7 @@ func TestRbfCloseClosingNegotiationLocal(t *testing.T) {
16141614
// Next, we'll send in a new SendOfferEvent event which
16151615
// simulates the user requesting a RBF fee bump. We'll use 10x
16161616
// the fee we used in the last iteration.
1617-
rbfFeeBump := chainfee.FeePerKwFloor.FeePerVByte() * 10
1617+
rbfFeeBump := chainfee.FeePerKwFloor * 10
16181618
localOffer := &SendOfferEvent{
16191619
TargetFeeRate: rbfFeeBump,
16201620
}
@@ -1649,7 +1649,7 @@ func TestRbfCloseClosingNegotiationLocal(t *testing.T) {
16491649
// the amount we have in the channel.
16501650
closeHarness.expectFeeEstimate(btcutil.SatoshiPerBitcoin, 1)
16511651

1652-
rbfFeeBump := chainfee.FeePerKwFloor.FeePerVByte()
1652+
rbfFeeBump := chainfee.FeePerKwFloor
16531653
localOffer := &SendOfferEvent{
16541654
TargetFeeRate: rbfFeeBump,
16551655
}
@@ -1997,7 +1997,7 @@ func TestRbfCloseErr(t *testing.T) {
19971997
})
19981998
defer closeHarness.stopAndAssert()
19991999

2000-
rbfFeeBump := chainfee.FeePerKwFloor.FeePerVByte()
2000+
rbfFeeBump := chainfee.FeePerKwFloor
20012001
localOffer := &SendOfferEvent{
20022002
TargetFeeRate: rbfFeeBump,
20032003
}

lnwallet/chancloser/rbf_coop_transitions.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"fmt"
66

7+
"github.com/btcsuite/btcd/blockchain"
78
"github.com/btcsuite/btcd/btcec/v2"
89
"github.com/btcsuite/btcd/btcutil"
910
"github.com/btcsuite/btcd/chaincfg"
@@ -509,7 +510,7 @@ func (c *ChannelFlushing) ProcessEvent(event ProtocolEvent,
509510
localTxOut, remoteTxOut := closeTerms.DeriveCloseTxOuts()
510511
absoluteFee := env.FeeEstimator.EstimateFee(
511512
env.ChanType, localTxOut, remoteTxOut,
512-
idealFeeRate.FeePerKWeight(),
513+
idealFeeRate,
513514
)
514515

515516
chancloserLog.Infof("ChannelPoint(%v): using ideal_fee=%v, "+
@@ -752,7 +753,7 @@ func (l *LocalCloseStart) ProcessEvent(event ProtocolEvent,
752753
localTxOut, remoteTxOut := l.DeriveCloseTxOuts()
753754
absoluteFee := env.FeeEstimator.EstimateFee(
754755
env.ChanType, localTxOut, remoteTxOut,
755-
msg.TargetFeeRate.FeePerKWeight(),
756+
msg.TargetFeeRate,
756757
)
757758

758759
// If we can't actually pay for fees here, then we'll just do a
@@ -1128,11 +1129,16 @@ func (l *RemoteCloseStart) ProcessEvent(event ProtocolEvent,
11281129
// We'll also compute the final fee rate that the remote party
11291130
// paid based off the absolute fee and the size of the closing
11301131
// transaction.
1131-
vSize := mempool.GetTxVirtualSize(btcutil.NewTx(closeTx))
1132-
feeRate := chainfee.SatPerVByte(
1133-
int64(msg.SigMsg.FeeSatoshis) / vSize,
1132+
weight := blockchain.GetTransactionWeight(
1133+
btcutil.NewTx(closeTx),
11341134
)
11351135

1136+
// Convert absolute fee to a fee rate in sat/kw, rounding up.
1137+
fee := int64(msg.SigMsg.FeeSatoshis)
1138+
rate := ((fee * 1000) + weight - 1) / weight
1139+
1140+
feeRate := chainfee.SatPerKWeight(rate)
1141+
11361142
// Now that we've extracted the signature, we'll transition to
11371143
// the next state where we'll sign+broadcast the sig.
11381144
return &CloseStateTransition{

peer/brontide.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,10 @@ type PendingUpdate struct {
150150
// transaction.
151151
OutputIndex uint32
152152

153-
// FeePerVByte is an optional field, that is set only when the new RBF
153+
// FeePerKw is an optional field, that is set only when the new RBF
154154
// coop close flow is used. This indicates the new closing fee rate on
155155
// the closing transaction.
156-
FeePerVbyte fn.Option[chainfee.SatPerVByte]
156+
FeePerKw fn.Option[chainfee.SatPerKWeight]
157157

158158
// IsLocalCloseTx is an optional field that indicates if this update is
159159
// sent for our local close txn, or the close txn of the remote party.
@@ -3611,7 +3611,7 @@ func (p *Brontide) observeRbfCloseUpdates(chanCloser *chancloser.RbfChanCloser,
36113611

36123612
var (
36133613
lastTxids lntypes.Dual[chainhash.Hash]
3614-
lastFeeRates lntypes.Dual[chainfee.SatPerVByte]
3614+
lastFeeRates lntypes.Dual[chainfee.SatPerKWeight]
36153615
)
36163616

36173617
maybeNotifyTxBroadcast := func(state chancloser.AsymmetricPeerState,
@@ -3670,8 +3670,8 @@ func (p *Brontide) observeRbfCloseUpdates(chanCloser *chancloser.RbfChanCloser,
36703670
if closeReq != nil && closingTxid != lastTxid {
36713671
select {
36723672
case closeReq.Updates <- &PendingUpdate{
3673-
Txid: closingTxid[:],
3674-
FeePerVbyte: fn.Some(closePending.FeeRate),
3673+
Txid: closingTxid[:],
3674+
FeePerKw: fn.Some(closePending.FeeRate),
36753675
IsLocalCloseTx: fn.Some(
36763676
party == lntypes.Local,
36773677
),
@@ -3928,7 +3928,7 @@ func (p *Brontide) initRbfChanCloser(
39283928
ChanID: chanID,
39293929
Scid: scid,
39303930
ChanType: channel.ChanType(),
3931-
DefaultFeeRate: defaultFeePerKw.FeePerVByte(),
3931+
DefaultFeeRate: defaultFeePerKw,
39323932
ThawHeight: fn.Some(thawHeight),
39333933
RemoteUpfrontShutdown: ChooseAddr(
39343934
channel.RemoteUpfrontShutdownScript(),
@@ -4189,7 +4189,7 @@ func (p *Brontide) startRbfChanCloser(shutdown shutdownInit,
41894189
}
41904190

41914191
ctx, _ := p.cg.Create(context.Background())
4192-
feeRate := defaultFeePerKw.FeePerVByte()
4192+
feeRate := defaultFeePerKw
41934193

41944194
// Depending on the state of the state machine, we'll either
41954195
// kick things off by sending shutdown, or attempt to send a new

rpcserver.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,8 +3137,8 @@ func createRPCCloseUpdate(
31373137
u.IsLocalCloseTx.WhenSome(func(isLocal bool) {
31383138
upd.LocalCloseTx = isLocal
31393139
})
3140-
u.FeePerVbyte.WhenSome(func(feeRate chainfee.SatPerVByte) {
3141-
upd.FeePerVbyte = int64(feeRate)
3140+
u.FeePerKw.WhenSome(func(feeRate chainfee.SatPerKWeight) {
3141+
upd.FeePerKw = uint64(feeRate)
31423142
})
31433143

31443144
return &lnrpc.CloseStatusUpdate{

0 commit comments

Comments
 (0)