mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
The Parameters struct describes the keys, expiry and pkScript that define the static address script, so its natural home is the script package. Moving it there lets staticutil drop its dependency on the address package and lets callers reuse a single type alongside script.StaticAddress and script.NewStaticAddress. No behavior change. Closes #1056
157 lines
4.5 KiB
Go
157 lines
4.5 KiB
Go
package loopin
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/lightninglabs/lndclient"
|
|
"github.com/lightninglabs/loop/staticaddr/deposit"
|
|
"github.com/lightninglabs/loop/staticaddr/script"
|
|
"github.com/lightninglabs/loop/staticaddr/version"
|
|
"github.com/lightningnetwork/lnd/input"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// noopSigner is a minimal SignerClient mock that returns dummy signatures
|
|
// without blocking on channels.
|
|
type noopSigner struct {
|
|
lndclient.SignerClient
|
|
}
|
|
|
|
// SignOutputRaw returns dummy 64-byte signatures for each sign descriptor.
|
|
func (s *noopSigner) SignOutputRaw(_ context.Context, _ *wire.MsgTx,
|
|
descs []*lndclient.SignDescriptor, _ []*wire.TxOut) ([][]byte, error) {
|
|
|
|
sigs := make([][]byte, len(descs))
|
|
for i := range descs {
|
|
sigs[i] = make([]byte, 64)
|
|
}
|
|
|
|
return sigs, nil
|
|
}
|
|
|
|
// TestCreateHtlcSweepTxSweepValue verifies that createHtlcSweepTx derives the
|
|
// sweep output value from the HTLC output, not the change output. When a change
|
|
// output is present, the sweep must reference the HTLC output value.
|
|
func TestCreateHtlcSweepTxSweepValue(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
clientKey, err := btcec.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
serverKey, err := btcec.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
network := &chaincfg.RegressionNetParams
|
|
swapHash := lntypes.Hash{1, 2, 3}
|
|
|
|
// Create a static address to derive PkScript.
|
|
staticAddr, err := newStaticAddress(
|
|
clientKey.PubKey(), serverKey.PubKey(), 4032,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
pkScript, err := staticAddr.StaticAddressScript()
|
|
require.NoError(t, err)
|
|
|
|
addrParams := &script.Parameters{
|
|
ClientPubkey: clientKey.PubKey(),
|
|
ServerPubkey: serverKey.PubKey(),
|
|
PkScript: pkScript,
|
|
Expiry: 4032,
|
|
ProtocolVersion: version.ProtocolVersion_V0,
|
|
}
|
|
|
|
depositValue := btcutil.Amount(500_000)
|
|
deposits := []*deposit.Deposit{
|
|
{
|
|
OutPoint: wire.OutPoint{
|
|
Hash: chainhash.Hash{0xaa},
|
|
Index: 0,
|
|
},
|
|
Value: depositValue,
|
|
},
|
|
}
|
|
|
|
feeRate := chainfee.SatPerKWeight(253)
|
|
maxFeePercentage := 0.2
|
|
|
|
// SelectedAmount < total triggers a change output.
|
|
selectedAmount := btcutil.Amount(300_000)
|
|
|
|
loopIn := &StaticAddressLoopIn{
|
|
SwapHash: swapHash,
|
|
HtlcCltvExpiry: 800,
|
|
InitiationHeight: 100,
|
|
InitiationTime: time.Now(),
|
|
ProtocolVersion: version.ProtocolVersion_V0,
|
|
ClientPubkey: clientKey.PubKey(),
|
|
ServerPubkey: serverKey.PubKey(),
|
|
Deposits: deposits,
|
|
AddressParams: addrParams,
|
|
HtlcTxFeeRate: feeRate,
|
|
SelectedAmount: selectedAmount,
|
|
PaymentTimeoutSeconds: 3600,
|
|
}
|
|
|
|
sweepAddr, err := btcutil.NewAddressTaproot(
|
|
make([]byte, 32), network,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
signer := &noopSigner{}
|
|
|
|
// Build the HTLC transaction once. It has two outputs with distinct
|
|
// values: the HTLC output and a change output.
|
|
htlcTx, err := loopIn.createHtlcTx(network, feeRate, maxFeePercentage)
|
|
require.NoError(t, err)
|
|
require.Len(t, htlcTx.TxOut, 2, "expected HTLC + change outputs")
|
|
|
|
// Identify which output is change and which is HTLC.
|
|
var htlcIdx int
|
|
if bytes.Equal(htlcTx.TxOut[0].PkScript, pkScript) {
|
|
htlcIdx = 1
|
|
}
|
|
|
|
htlcValue := htlcTx.TxOut[htlcIdx].Value
|
|
changeValue := htlcTx.TxOut[1-htlcIdx].Value
|
|
require.NotEqual(t, htlcValue, changeValue,
|
|
"HTLC and change values must differ for this test to be "+
|
|
"meaningful")
|
|
|
|
// Call createHtlcSweepTx and verify that the sweep output is derived
|
|
// from the HTLC value, not the change.
|
|
sweepTx, err := loopIn.createHtlcSweepTx(
|
|
t.Context(), signer, sweepAddr, feeRate,
|
|
network, uint32(loopIn.HtlcCltvExpiry)+1,
|
|
maxFeePercentage,
|
|
)
|
|
require.NoError(t, err)
|
|
require.Len(t, sweepTx.TxOut, 1)
|
|
|
|
sweepValue := sweepTx.TxOut[0].Value
|
|
require.Greater(t, sweepValue, int64(0))
|
|
require.LessOrEqual(t, sweepValue, htlcValue,
|
|
"sweep value must not exceed HTLC output value")
|
|
require.Greater(t, sweepValue, changeValue,
|
|
"sweep value should be greater than change "+
|
|
"value, confirming it was derived from "+
|
|
"the HTLC output")
|
|
}
|
|
|
|
// newStaticAddress creates a StaticAddress for testing.
|
|
func newStaticAddress(clientKey, serverKey *btcec.PublicKey,
|
|
csvExpiry int64) (*script.StaticAddress, error) {
|
|
|
|
return script.NewStaticAddress(
|
|
input.MuSig2Version100RC2, csvExpiry, clientKey, serverKey,
|
|
)
|
|
}
|