graph/db: add v2 channel announcement fields to ChannelEdgeInfo
This commit extends ChannelEdgeInfo to support v2 (taproot) channel announcements by adding: - MerkleRootHash for the optional Merkle tree commitment - ExtraSignedFields for additional signed TLV fields - ChannelV2Fields struct to encapsulate v2-specific optional fields - NewV2Channel constructor for creating v2 channel edges - FundingPKScript handling for MuSig2 key aggregation with optional taproot tweaks
This commit is contained in:
2 files changed
+274
No files matched your search
@@ -0,0 +1,147 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestFundingPKScriptV2 tests the FundingPKScript method for v2 channels
|
||||
// which uses MuSig2 key aggregation.
|
||||
func TestFundingPKScriptV2(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Generate two test keys for bitcoin keys.
|
||||
privKey1, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
pubKey1 := privKey1.PubKey()
|
||||
|
||||
privKey2, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
pubKey2 := privKey2.PubKey()
|
||||
|
||||
// Convert to route.Vertex format.
|
||||
var btcKey1, btcKey2 route.Vertex
|
||||
copy(btcKey1[:], pubKey1.SerializeCompressed())
|
||||
copy(btcKey2[:], pubKey2.SerializeCompressed())
|
||||
|
||||
// Create a test merkle root.
|
||||
var merkleRoot chainhash.Hash
|
||||
copy(merkleRoot[:], []byte("test-merkle-root-hash-32-bytes!"))
|
||||
|
||||
t.Run("v2 with btc keys, no merkle root (BIP86)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
edge := &ChannelEdgeInfo{
|
||||
Version: lnwire.GossipVersion2,
|
||||
BitcoinKey1Bytes: fn.Some(btcKey1),
|
||||
BitcoinKey2Bytes: fn.Some(btcKey2),
|
||||
}
|
||||
|
||||
pkScript, err := edge.FundingPKScript()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, pkScript)
|
||||
|
||||
// Verify it's a valid taproot script (OP_1 <32-byte-key>).
|
||||
require.Len(t, pkScript, 34)
|
||||
require.Equal(t, byte(0x51), pkScript[0]) // OP_1
|
||||
|
||||
// Manually compute expected script using BIP86 tweak.
|
||||
combinedKey, _, _, err := musig2.AggregateKeys(
|
||||
[]*btcec.PublicKey{pubKey1, pubKey2}, true,
|
||||
musig2.WithBIP86KeyTweak(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedScript, err := input.PayToTaprootScript(
|
||||
combinedKey.FinalKey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedScript, pkScript)
|
||||
})
|
||||
|
||||
t.Run("v2 with bitcoin keys and merkle root", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
edge := &ChannelEdgeInfo{
|
||||
Version: lnwire.GossipVersion2,
|
||||
BitcoinKey1Bytes: fn.Some(btcKey1),
|
||||
BitcoinKey2Bytes: fn.Some(btcKey2),
|
||||
MerkleRootHash: fn.Some(merkleRoot),
|
||||
}
|
||||
|
||||
pkScript, err := edge.FundingPKScript()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, pkScript)
|
||||
|
||||
// Verify it's a valid taproot script.
|
||||
require.Len(t, pkScript, 34)
|
||||
require.Equal(t, byte(0x51), pkScript[0]) // OP_1
|
||||
|
||||
// Manually compute expected script with taproot tweak.
|
||||
combinedKey, _, _, err := musig2.AggregateKeys(
|
||||
[]*btcec.PublicKey{pubKey1, pubKey2}, true,
|
||||
musig2.WithTaprootKeyTweak(merkleRoot[:]),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedScript, err := input.PayToTaprootScript(
|
||||
combinedKey.FinalKey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedScript, pkScript)
|
||||
})
|
||||
|
||||
t.Run("v2 no btc keys returns stored script", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
storedScript := []byte{0x51, 0x20} // OP_1 + push 32
|
||||
storedScript = append(storedScript, make([]byte, 32)...)
|
||||
|
||||
edge := &ChannelEdgeInfo{
|
||||
Version: lnwire.GossipVersion2,
|
||||
FundingScript: fn.Some(storedScript),
|
||||
}
|
||||
|
||||
pkScript, err := edge.FundingPKScript()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, storedScript, pkScript)
|
||||
})
|
||||
|
||||
t.Run("v2 no btc keys and no stored script errors", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
edge := &ChannelEdgeInfo{
|
||||
Version: lnwire.GossipVersion2,
|
||||
}
|
||||
|
||||
_, err := edge.FundingPKScript()
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "expected a funding pk script")
|
||||
})
|
||||
|
||||
t.Run("v2 one btc key returns stored script", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
storedScript := []byte{0x51, 0x20}
|
||||
storedScript = append(storedScript, make([]byte, 32)...)
|
||||
|
||||
// Only key1 set, key2 missing.
|
||||
edge := &ChannelEdgeInfo{
|
||||
Version: lnwire.GossipVersion2,
|
||||
BitcoinKey1Bytes: fn.Some(btcKey1),
|
||||
FundingScript: fn.Some(storedScript),
|
||||
}
|
||||
|
||||
pkScript, err := edge.FundingPKScript()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, storedScript, pkScript)
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user