mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-14 12:43:03 +02:00
Update LND, Aperture, and Taproot Assets to revisions using the btcd v2 modules, and update lndclient to v0.21.0-3. Migrate Loop chain, transaction, and address types to their corresponding v2 packages. The lndclient release includes the migration from: https://github.com/lightninglabs/lndclient/pull/280 Taproot Assets is temporarily replaced with its btcd v2 revision because the v0.8 release branch has not adopted the new modules. This raises the minimum Go version to 1.26 and changes exported address types.
194 lines
5.4 KiB
Go
194 lines
5.4 KiB
Go
package loopin
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
btcaddr "github.com/btcsuite/btcd/address/v2"
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/btcutil/v2"
|
|
"github.com/btcsuite/btcd/chaincfg/v2"
|
|
"github.com/btcsuite/btcd/chainhash/v2"
|
|
"github.com/btcsuite/btcd/wire/v2"
|
|
"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 := btcaddr.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")
|
|
}
|
|
|
|
// TestPaymentTimeoutDuration verifies that zero timeout values fall back to the
|
|
// default payment timeout duration.
|
|
func TestPaymentTimeoutDuration(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
paymentTimeoutSeconds uint32
|
|
expected time.Duration
|
|
}{
|
|
{
|
|
name: "default",
|
|
expected: time.Duration(DefaultPaymentTimeoutSeconds) * time.Second,
|
|
},
|
|
{
|
|
name: "configured",
|
|
paymentTimeoutSeconds: 42,
|
|
expected: 42 * time.Second,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
loopIn := &StaticAddressLoopIn{
|
|
PaymentTimeoutSeconds: test.paymentTimeoutSeconds,
|
|
}
|
|
|
|
require.Equal(
|
|
t, test.expected, loopIn.PaymentTimeoutDuration(),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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,
|
|
)
|
|
}
|