mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-26 01:33:02 +01:00
lnwallet: implement special case for OP_RETURN in rbf-coop
In this commit, we implement a special case for OP_RETURN scripts outlined in the spec. If a party decides that its output will be too small even after the dust check, then they can opt to set it to zero by sending an `OP_RETURN` as their script.
This commit is contained in:
parent
e6d7a1a2ec
commit
333492e657
@ -9269,13 +9269,19 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
|
||||
closeTx.LockTime = lockTime
|
||||
})
|
||||
|
||||
// TODO(roasbeef): needs support for dropping inputs
|
||||
|
||||
// Create both cooperative closure outputs, properly respecting the
|
||||
// dust limits of both parties.
|
||||
// Create both cooperative closure outputs, properly respecting the dust
|
||||
// limits of both parties.
|
||||
var localOutputIdx fn.Option[int]
|
||||
haveLocalOutput := ourBalance >= localDust
|
||||
if haveLocalOutput {
|
||||
// If our script is an OP_RETURN, then we set our balance to
|
||||
// zero.
|
||||
if opts.customSequence.IsSome() &&
|
||||
input.ScriptIsOpReturn(ourDeliveryScript) {
|
||||
|
||||
ourBalance = 0
|
||||
}
|
||||
|
||||
closeTx.AddTxOut(&wire.TxOut{
|
||||
PkScript: ourDeliveryScript,
|
||||
Value: int64(ourBalance),
|
||||
@ -9287,6 +9293,14 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
|
||||
var remoteOutputIdx fn.Option[int]
|
||||
haveRemoteOutput := theirBalance >= remoteDust
|
||||
if haveRemoteOutput {
|
||||
// If a party's script is an OP_RETURN, then we set their
|
||||
// balance to zero.
|
||||
if opts.customSequence.IsSome() &&
|
||||
input.ScriptIsOpReturn(theirDeliveryScript) {
|
||||
|
||||
theirBalance = 0
|
||||
}
|
||||
|
||||
closeTx.AddTxOut(&wire.TxOut{
|
||||
PkScript: theirDeliveryScript,
|
||||
Value: int64(theirBalance),
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/btcutil/txsort"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/mempool"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
@ -2450,6 +2451,72 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCooperativeCloseOpReturn tests that if either party's script is an
|
||||
// OP_RETURN script, then we'll set their output value as zero on the closing
|
||||
// transaction.
|
||||
func TestCooperativeCloseOpReturn(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test channel which will be used for the duration of this
|
||||
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||
// and Bob having 5 BTC.
|
||||
aliceChannel, bobChannel, err := CreateTestChannels(
|
||||
t, channeldb.SingleFunderTweaklessBit,
|
||||
)
|
||||
require.NoError(t, err, "unable to create test channels")
|
||||
|
||||
// Alice will have a "normal" looking script, while Bob will have a
|
||||
// script that's just an OP_RETURN.
|
||||
aliceDeliveryScript := bobsPrivKey
|
||||
bobDeliveryScript := []byte{txscript.OP_RETURN}
|
||||
|
||||
aliceFeeRate := chainfee.SatPerKWeight(
|
||||
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||
)
|
||||
aliceFee := aliceChannel.CalcFee(aliceFeeRate) + 1000
|
||||
|
||||
assertBobOpReturn := func(tx *wire.MsgTx) {
|
||||
// We should still have two outputs on the commitment
|
||||
// transaction, as Alice's is non-dust.
|
||||
require.Len(t, tx.TxOut, 2)
|
||||
|
||||
// We should find that Bob's output has a zero value.
|
||||
bobTxOut := fn.Filter(tx.TxOut, func(txOut *wire.TxOut) bool {
|
||||
return bytes.Equal(txOut.PkScript, bobDeliveryScript)
|
||||
})
|
||||
require.Len(t, bobTxOut, 1)
|
||||
|
||||
require.True(t, bobTxOut[0].Value == 0)
|
||||
}
|
||||
|
||||
// Next, we'll make a new co-op close proposal, initiated by Alice.
|
||||
aliceSig, closeTxAlice, _, err := aliceChannel.CreateCloseProposal(
|
||||
aliceFee, aliceDeliveryScript, bobDeliveryScript,
|
||||
// We use a custom sequence as this rule only applies to the RBF
|
||||
// coop channel type.
|
||||
WithCustomSequence(mempool.MaxRBFSequence),
|
||||
)
|
||||
require.NoError(t, err, "unable to close channel")
|
||||
|
||||
assertBobOpReturn(closeTxAlice)
|
||||
|
||||
bobSig, _, _, err := bobChannel.CreateCloseProposal(
|
||||
aliceFee, bobDeliveryScript, aliceDeliveryScript,
|
||||
WithCustomSequence(mempool.MaxRBFSequence),
|
||||
)
|
||||
require.NoError(t, err, "unable to close channel")
|
||||
|
||||
// We should now be able to complete the cooperative channel closure,
|
||||
// finding that the close tx still only has a single output.
|
||||
closeTx, _, err := bobChannel.CompleteCooperativeClose(
|
||||
bobSig, aliceSig, bobDeliveryScript, aliceDeliveryScript,
|
||||
aliceFee, WithCustomSequence(mempool.MaxRBFSequence),
|
||||
)
|
||||
require.NoError(t, err, "unable to accept channel close")
|
||||
|
||||
assertBobOpReturn(closeTx)
|
||||
}
|
||||
|
||||
// TestUpdateFeeAdjustments tests that the state machine is able to properly
|
||||
// accept valid fee changes, as well as reject any invalid fee updates.
|
||||
func TestUpdateFeeAdjustments(t *testing.T) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user