| 
 | 1 | +package tapchannel  | 
 | 2 | + | 
 | 3 | +import (  | 
 | 4 | +	"bytes"  | 
 | 5 | +	"crypto/rand"  | 
 | 6 | +	"encoding/hex"  | 
 | 7 | +	"fmt"  | 
 | 8 | +	"testing"  | 
 | 9 | + | 
 | 10 | +	"github.com/btcsuite/btcd/btcec/v2"  | 
 | 11 | +	"github.com/btcsuite/btcd/btcec/v2/ecdsa"  | 
 | 12 | +	"github.com/btcsuite/btcd/txscript"  | 
 | 13 | +	"github.com/lightninglabs/taproot-assets/asset"  | 
 | 14 | +	cmsg "github.com/lightninglabs/taproot-assets/tapchannelmsg"  | 
 | 15 | +	"github.com/lightningnetwork/lnd/input"  | 
 | 16 | +	"github.com/lightningnetwork/lnd/lnwire"  | 
 | 17 | +	"github.com/lightningnetwork/lnd/tlv"  | 
 | 18 | +	"github.com/stretchr/testify/require"  | 
 | 19 | +)  | 
 | 20 | + | 
 | 21 | +// Some of these test values and functions are from lnd's lnwire/lnwire_test.go.  | 
 | 22 | +var (  | 
 | 23 | +	testRBytes, _ = hex.DecodeString(  | 
 | 24 | +		"8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f8" +  | 
 | 25 | +			"82d7",  | 
 | 26 | +	)  | 
 | 27 | +	testSBytes, _ = hex.DecodeString(  | 
 | 28 | +		"299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d" +  | 
 | 29 | +			"24ae",  | 
 | 30 | +	)  | 
 | 31 | +	testRScalar = new(btcec.ModNScalar)  | 
 | 32 | +	testSScalar = new(btcec.ModNScalar)  | 
 | 33 | +	_           = testRScalar.SetByteSlice(testRBytes)  | 
 | 34 | +	_           = testSScalar.SetByteSlice(testSBytes)  | 
 | 35 | +	testSig     = ecdsa.NewSignature(testRScalar, testSScalar)  | 
 | 36 | + | 
 | 37 | +	testSchnorrSigStr, _ = hex.DecodeString(  | 
 | 38 | +		"04e7f9037658a92afeb4f25bae5339e3ddca81a353493827d26f16d92308" +  | 
 | 39 | +			"e49e2a25e92208678a2df86970da91b03a8af8815a8a60498b35" +  | 
 | 40 | +			"8daf560b347aa557",  | 
 | 41 | +	)  | 
 | 42 | +	testSchnorrSig, _ = lnwire.NewSigFromSchnorrRawSignature(  | 
 | 43 | +		testSchnorrSigStr,  | 
 | 44 | +	)  | 
 | 45 | + | 
 | 46 | +	minNumHTLCs = 5  | 
 | 47 | +	maxNumHTLCs = input.MaxHTLCNumber  | 
 | 48 | +)  | 
 | 49 | + | 
 | 50 | +func randPartialSigWithNonce() (*lnwire.PartialSigWithNonce, error) {  | 
 | 51 | +	var sigBytes [32]byte  | 
 | 52 | +	if _, err := rand.Read(sigBytes[:]); err != nil {  | 
 | 53 | +		return nil, fmt.Errorf("unable to generate sig: %w", err)  | 
 | 54 | +	}  | 
 | 55 | + | 
 | 56 | +	var s btcec.ModNScalar  | 
 | 57 | +	s.SetByteSlice(sigBytes[:])  | 
 | 58 | + | 
 | 59 | +	var nonce lnwire.Musig2Nonce  | 
 | 60 | +	if _, err := rand.Read(nonce[:]); err != nil {  | 
 | 61 | +		return nil, fmt.Errorf("unable to generate nonce: %w", err)  | 
 | 62 | +	}  | 
 | 63 | + | 
 | 64 | +	return &lnwire.PartialSigWithNonce{  | 
 | 65 | +		PartialSig: lnwire.NewPartialSig(s),  | 
 | 66 | +		Nonce:      nonce,  | 
 | 67 | +	}, nil  | 
 | 68 | +}  | 
 | 69 | + | 
 | 70 | +func somePartialSigWithNonce(t *testing.T) lnwire.OptPartialSigWithNonceTLV {  | 
 | 71 | +	sig, err := randPartialSigWithNonce()  | 
 | 72 | +	if err != nil {  | 
 | 73 | +		t.Fatal(err)  | 
 | 74 | +	}  | 
 | 75 | + | 
 | 76 | +	return tlv.SomeRecordT(tlv.NewRecordT[  | 
 | 77 | +		lnwire.PartialSigWithNonceType,  | 
 | 78 | +		lnwire.PartialSigWithNonce,  | 
 | 79 | +	](*sig))  | 
 | 80 | +}  | 
 | 81 | + | 
 | 82 | +// TestMaxCommitSigMsgSize attempts to find values for the max number of asset  | 
 | 83 | +// IDs we want to allow per channel and the resulting maximum number of HTLCs  | 
 | 84 | +// that channel can allow. The maximum number of different asset IDs that can be  | 
 | 85 | +// committed to a channel directly impacts the number of HTLCs that can be  | 
 | 86 | +// created on that channel, because we have a limited message size to exchange  | 
 | 87 | +// the second-stage HTLC signatures. The goal of this test is to find the right  | 
 | 88 | +// number of asset IDs we should allow per channel to still give us a reasonable  | 
 | 89 | +// amount of HTLCs.  | 
 | 90 | +func TestMaxCommitSigMsgSize(t *testing.T) {  | 
 | 91 | +	const maxNumAssetIDs = 10  | 
 | 92 | + | 
 | 93 | +	var buf bytes.Buffer  | 
 | 94 | +	for numID := 0; numID <= maxNumAssetIDs; numID++ {  | 
 | 95 | +		for numHTLC := minNumHTLCs; numHTLC <= maxNumHTLCs; numHTLC++ {  | 
 | 96 | +			buf.Reset()  | 
 | 97 | + | 
 | 98 | +			msg := makeCommitSig(t, numID, numHTLC)  | 
 | 99 | +			err := msg.Encode(&buf, 0)  | 
 | 100 | +			require.NoError(t, err)  | 
 | 101 | + | 
 | 102 | +			if buf.Len() > lnwire.MaxMsgBody {  | 
 | 103 | +				t.Logf("Last valid commit sig msg size with: "+  | 
 | 104 | +					"numAssetIDs=%d, numHTLCs=%d",  | 
 | 105 | +					numID, numHTLC-1)  | 
 | 106 | + | 
 | 107 | +				break  | 
 | 108 | +			}  | 
 | 109 | + | 
 | 110 | +			if numHTLC == maxNumHTLCs {  | 
 | 111 | +				t.Logf("Last valid commit sig msg size with: "+  | 
 | 112 | +					"numAssetIDs=%d, numHTLCs=%d",  | 
 | 113 | +					numID, numHTLC)  | 
 | 114 | +			}  | 
 | 115 | +		}  | 
 | 116 | +	}  | 
 | 117 | +}  | 
 | 118 | + | 
 | 119 | +func makeCommitSig(t *testing.T, numAssetIDs, numHTLCs int) *lnwire.CommitSig {  | 
 | 120 | +	var (  | 
 | 121 | +		msg = &lnwire.CommitSig{  | 
 | 122 | +			HtlcSigs: make([]lnwire.Sig, numHTLCs),  | 
 | 123 | +		}  | 
 | 124 | +		err error  | 
 | 125 | +	)  | 
 | 126 | + | 
 | 127 | +	// Static values that are always set for custom channels (which are  | 
 | 128 | +	// Taproot channels, so have an all-zero legacy commit signature and a  | 
 | 129 | +	// partial MuSig2 signature).  | 
 | 130 | +	msg.PartialSig = somePartialSigWithNonce(t)  | 
 | 131 | +	msg.CommitSig, err = lnwire.NewSigFromSignature(testSig)  | 
 | 132 | +	require.NoError(t, err)  | 
 | 133 | + | 
 | 134 | +	assetSigs := make([][]*cmsg.AssetSig, numHTLCs)  | 
 | 135 | +	for i := range numHTLCs {  | 
 | 136 | +		msg.HtlcSigs[i] = testSchnorrSig  | 
 | 137 | + | 
 | 138 | +		assetSigs[i] = make([]*cmsg.AssetSig, numAssetIDs)  | 
 | 139 | +		for j := range numAssetIDs {  | 
 | 140 | +			var assetID asset.ID  | 
 | 141 | + | 
 | 142 | +			_, err := rand.Read(assetID[:])  | 
 | 143 | +			require.NoError(t, err)  | 
 | 144 | + | 
 | 145 | +			assetSigs[i][j] = cmsg.NewAssetSig(  | 
 | 146 | +				assetID, testSchnorrSig, txscript.SigHashAll,  | 
 | 147 | +			)  | 
 | 148 | +		}  | 
 | 149 | +	}  | 
 | 150 | + | 
 | 151 | +	if numAssetIDs == 0 {  | 
 | 152 | +		return msg  | 
 | 153 | +	}  | 
 | 154 | + | 
 | 155 | +	commitSig := cmsg.NewCommitSig(assetSigs)  | 
 | 156 | + | 
 | 157 | +	var buf bytes.Buffer  | 
 | 158 | +	err = commitSig.Encode(&buf)  | 
 | 159 | +	require.NoError(t, err)  | 
 | 160 | + | 
 | 161 | +	msg.CustomRecords = lnwire.CustomRecords{  | 
 | 162 | +		65543: buf.Bytes(),  | 
 | 163 | +	}  | 
 | 164 | + | 
 | 165 | +	return msg  | 
 | 166 | +}  | 
0 commit comments