Skip to content

Commit 1302d08

Browse files
committed
assets: add no-csv option to the asset HTLC to support package relay
This commit enables package relayed HTLCs by making the CSV check in the success path optional.
1 parent 5865630 commit 1302d08

File tree

2 files changed

+36
-13
lines changed

2 files changed

+36
-13
lines changed

assets/htlc/script.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import (
1111
"github.com/lightningnetwork/lnd/lntypes"
1212
)
1313

14-
// GenSuccessPathScript constructs an HtlcScript for the success payment path.
14+
// GenSuccessPathScript constructs a script for the success path of the HTLC
15+
// payment. Optionally includes a CHECKSEQUENCEVERIFY (CSV) of 1 if `csv` is
16+
// true, to prevent potential pinning attacks when the HTLC is not part of a
17+
// package relay.
1518
func GenSuccessPathScript(receiverHtlcKey *btcec.PublicKey,
16-
swapHash lntypes.Hash) ([]byte, error) {
19+
swapHash lntypes.Hash, csvOne bool) ([]byte, error) {
1720

1821
builder := txscript.NewScriptBuilder()
1922

@@ -24,9 +27,22 @@ func GenSuccessPathScript(receiverHtlcKey *btcec.PublicKey,
2427
builder.AddOp(txscript.OP_EQUALVERIFY)
2528
builder.AddOp(txscript.OP_HASH160)
2629
builder.AddData(input.Ripemd160H(swapHash[:]))
27-
builder.AddOp(txscript.OP_EQUALVERIFY)
28-
builder.AddInt64(1)
29-
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
30+
// OP_EQUAL will leave 0 or 1 on the stack depending on whether the the
31+
// hash matches.
32+
// - If it matches and CSV is not used, the script will
33+
// evaulate to true.
34+
// - If it matches and CSV is used, we'll have 1 on the stack which is
35+
// used to verify the CSV condition.
36+
// - If it does not match, we'll have 0 on the stack which will cause
37+
// the script to fail even if CSV is used.
38+
builder.AddOp(txscript.OP_EQUAL)
39+
40+
if csvOne {
41+
// If csvOne is true, we add a CHECKSEQUENCEVERIFY to ensure
42+
// that the HTLC can only be claimed after at least one
43+
// confirmation.
44+
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
45+
}
3046

3147
return builder.Script()
3248
}
@@ -61,7 +77,9 @@ func CreateOpTrueLeaf() (asset.ScriptKey, txscript.TapLeaf,
6177
tapLeaf := txscript.NewBaseTapLeaf(tapScript)
6278
tree := txscript.AssembleTaprootScriptTree(tapLeaf)
6379
rootHash := tree.RootNode.TapHash()
64-
tapKey := txscript.ComputeTaprootOutputKey(asset.NUMSPubKey, rootHash[:])
80+
tapKey := txscript.ComputeTaprootOutputKey(
81+
asset.NUMSPubKey, rootHash[:],
82+
)
6583

6684
merkleRootHash := tree.RootNode.TapHash()
6785

assets/htlc/swapkit.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ type SwapKit struct {
4747
// AddressParams is the chain parameters of the chain the deposit is
4848
// being created on.
4949
AddressParams *address.ChainParams
50+
51+
// CheckCSV indicates whether the success path script should include a
52+
// CHECKSEQUENCEVERIFY check. This is used to prevent potential pinning
53+
// attacks when the HTLC is not part of a package relay.
54+
CheckCSV bool
5055
}
5156

5257
// GetSuccessScript returns the success path script of the swap HTLC.
5358
func (s *SwapKit) GetSuccessScript() ([]byte, error) {
54-
return GenSuccessPathScript(s.ReceiverPubKey, s.SwapHash)
59+
return GenSuccessPathScript(s.ReceiverPubKey, s.SwapHash, s.CheckCSV)
5560
}
5661

5762
// GetTimeoutScript returns the timeout path script of the swap HTLC.
@@ -158,10 +163,8 @@ func (s *SwapKit) CreateHtlcVpkt() (*tappsbt.VPacket, error) {
158163
ScriptKey: asset.NUMSScriptKey,
159164
})
160165
pkt.Outputs = append(pkt.Outputs, &tappsbt.VOutput{
161-
// todo(sputn1ck) assetversion
162-
AssetVersion: asset.Version(1),
166+
AssetVersion: asset.V1,
163167
Amount: uint64(s.Amount),
164-
Interactive: true,
165168
AnchorOutputIndex: 1,
166169
ScriptKey: asset.NewScriptKey(
167170
tapScriptKey.PubKey,
@@ -194,7 +197,7 @@ func (s *SwapKit) GenTimeoutBtcControlBlock(taprootAssetRoot []byte) (
194197
InternalKey: internalKey,
195198
LeafVersion: txscript.BaseLeafVersion,
196199
InclusionProof: append(
197-
successLeafHash[:], taprootAssetRoot[:]...,
200+
successLeafHash[:], taprootAssetRoot...,
198201
),
199202
}
200203

@@ -235,7 +238,7 @@ func (s *SwapKit) GenSuccessBtcControlBlock(taprootAssetRoot []byte) (
235238
InternalKey: internalKey,
236239
LeafVersion: txscript.BaseLeafVersion,
237240
InclusionProof: append(
238-
timeOutLeafHash[:], taprootAssetRoot[:]...,
241+
timeOutLeafHash[:], taprootAssetRoot...,
239242
),
240243
}
241244

@@ -324,7 +327,9 @@ func (s *SwapKit) CreatePreimageWitness(ctx context.Context,
324327
Value: sweepBtcPacket.Inputs[1].WitnessUtxo.Value,
325328
}
326329

327-
//sweepBtcPacket.UnsignedTx.TxIn[0].Sequence = 1
330+
if s.CheckCSV {
331+
sweepBtcPacket.UnsignedTx.TxIn[0].Sequence = 1
332+
}
328333

329334
successScript, err := s.GetSuccessScript()
330335
if err != nil {

0 commit comments

Comments
 (0)