Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lnwire+netann: update structure of g175 messages to be pure TLV #9175

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 39 additions & 15 deletions discovery/gossiper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightninglabs/neutrino/cache"
Expand Down Expand Up @@ -166,14 +168,9 @@ type PinnedSyncers map[route.Vertex]struct{}
// Config defines the configuration for the service. ALL elements within the
// configuration MUST be non-nil for the service to carry out its duties.
type Config struct {
// ChainHash is a hash that indicates which resident chain of the
// AuthenticatedGossiper. Any announcements that don't match this
// chain hash will be ignored.
//
// TODO(roasbeef): eventually make into map so can de-multiplex
// incoming announcements
// * also need to do same for Notifier
ChainHash chainhash.Hash
// ChainParams holds the chain parameters for the active network this
// node is participating on.
ChainParams *chaincfg.Params
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be a normal value rather than a pointer.


// Graph is the subsystem which is responsible for managing the
// topology of lightning network. After incoming channel, node, channel
Expand Down Expand Up @@ -359,6 +356,12 @@ type Config struct {
// updates for a channel and returns true if the channel should be
// considered a zombie based on these timestamps.
IsStillZombieChannel func(time.Time, time.Time) bool

// chainHash is a hash that indicates which resident chain of the
// AuthenticatedGossiper. Any announcements that don't match this
// chain hash will be ignored. This is an internal config value obtained
// from ChainParams.
chainHash *chainhash.Hash
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need it here if we have ChainParams?

}

// processedNetworkMsg is a wrapper around networkMsg and a boolean. It is
Expand Down Expand Up @@ -518,6 +521,8 @@ type AuthenticatedGossiper struct {
// New creates a new AuthenticatedGossiper instance, initialized with the
// passed configuration parameters.
func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper {
cfg.chainHash = cfg.ChainParams.GenesisHash

gossiper := &AuthenticatedGossiper{
selfKey: selfKeyDesc.PubKey,
selfKeyLoc: selfKeyDesc.KeyLocator,
Expand All @@ -538,7 +543,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper
}

gossiper.syncMgr = newSyncManager(&SyncManagerCfg{
ChainHash: cfg.ChainHash,
ChainHash: *cfg.chainHash,
ChanSeries: cfg.ChanSeries,
RotateTicker: cfg.RotateTicker,
HistoricalSyncTicker: cfg.HistoricalSyncTicker,
Expand Down Expand Up @@ -1946,9 +1951,28 @@ func (d *AuthenticatedGossiper) processRejectedEdge(

// fetchPKScript fetches the output script for the given SCID.
func (d *AuthenticatedGossiper) fetchPKScript(chanID *lnwire.ShortChannelID) (
[]byte, error) {
txscript.ScriptClass, btcutil.Address, error) {

pkScript, err := lnwallet.FetchPKScriptWithQuit(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the merkle proof case?

d.cfg.ChainIO, chanID, d.quit,
)
if err != nil {
return txscript.WitnessUnknownTy, nil, err
}

scriptClass, addrs, _, err := txscript.ExtractPkScriptAddrs(
pkScript, d.cfg.ChainParams,
)
if err != nil {
return txscript.WitnessUnknownTy, nil, err
}

if len(addrs) != 1 {
return txscript.WitnessUnknownTy, nil, fmt.Errorf("expected "+
"1 address, got: %d", len(addrs))
}

return lnwallet.FetchPKScriptWithQuit(d.cfg.ChainIO, chanID, d.quit)
return scriptClass, addrs[0], nil
}

// addNode processes the given node announcement, and adds it to our channel
Expand Down Expand Up @@ -2448,10 +2472,10 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,

// We'll ignore any channel announcements that target any chain other
// than the set of chains we know of.
if !bytes.Equal(ann.ChainHash[:], d.cfg.ChainHash[:]) {
if !bytes.Equal(ann.ChainHash[:], d.cfg.chainHash[:]) {
err := fmt.Errorf("ignoring ChannelAnnouncement1 from chain=%v"+
", gossiper on chain=%v", ann.ChainHash,
d.cfg.ChainHash)
d.cfg.chainHash)
log.Errorf(err.Error())

key := newRejectCacheKey(
Expand Down Expand Up @@ -2837,9 +2861,9 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,

// We'll ignore any channel updates that target any chain other than
// the set of chains we know of.
if !bytes.Equal(upd.ChainHash[:], d.cfg.ChainHash[:]) {
if !bytes.Equal(upd.ChainHash[:], d.cfg.chainHash[:]) {
err := fmt.Errorf("ignoring ChannelUpdate from chain=%v, "+
"gossiper on chain=%v", upd.ChainHash, d.cfg.ChainHash)
"gossiper on chain=%v", upd.ChainHash, d.cfg.chainHash)
log.Errorf(err.Error())

key := newRejectCacheKey(
Expand Down
5 changes: 4 additions & 1 deletion discovery/gossiper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
Expand Down Expand Up @@ -766,7 +767,8 @@ func createTestCtx(t *testing.T, startHeight uint32, isChanPeer bool) (
}

gossiper := New(Config{
Notifier: notifier,
ChainParams: &chaincfg.MainNetParams,
Notifier: notifier,
Broadcast: func(senders map[route.Vertex]struct{},
msgs ...lnwire.Message) error {

Expand Down Expand Up @@ -1480,6 +1482,7 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {

//nolint:lll
gossiper := New(Config{
ChainParams: &chaincfg.MainNetParams,
Notifier: ctx.gossiper.cfg.Notifier,
Broadcast: ctx.gossiper.cfg.Broadcast,
NotifyWhenOnline: ctx.gossiper.reliableSender.cfg.NotifyWhenOnline,
Expand Down
140 changes: 115 additions & 25 deletions netann/channel_announcement.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
Expand Down Expand Up @@ -108,7 +110,8 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,

// FetchPkScript defines a function that can be used to fetch the output script
// for the transaction with the given SCID.
type FetchPkScript func(*lnwire.ShortChannelID) ([]byte, error)
type FetchPkScript func(*lnwire.ShortChannelID) (txscript.ScriptClass,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the arg here need to be a pointer?

btcutil.Address, error)

// ValidateChannelAnn validates the channel announcement.
func ValidateChannelAnn(a lnwire.ChannelAnnouncement,
Expand Down Expand Up @@ -202,24 +205,124 @@ func validateChannelAnn1(a *lnwire.ChannelAnnouncement1) error {
func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,
fetchPkScript FetchPkScript) error {

// Next, we fetch the funding transaction's PK script. We need this so
// that we know what type of channel we will be validating: P2WSH or
// P2TR.
scriptClass, scriptAddr, err := fetchPkScript(&a.ShortChannelID.Val)
if err != nil {
return err
}

var keys []*btcec.PublicKey

switch scriptClass {
case txscript.WitnessV0ScriptHashTy:
keys, err = chanAnn2P2WSHMuSig2Keys(a)
if err != nil {
return err
}
case txscript.WitnessV1TaprootTy:
keys, err = chanAnn2P2TRMuSig2Keys(a, scriptAddr)
if err != nil {
return err
}
default:
return fmt.Errorf("invalid on-chain pk script type for "+
"channel_announcement_2: %s", scriptClass)
}

// Do a MuSig2 aggregation of the keys to obtain the aggregate key that
// the signature will be validated against.
aggKey, _, _, err := musig2.AggregateKeys(keys, true)
if err != nil {
return err
}

// Get the message that the signature should have signed.
dataHash, err := ChanAnn2DigestToSign(a)
if err != nil {
return err
}

// Obtain the signature.
sig, err := a.Signature.Val.ToSignature()
if err != nil {
return err
}

// Check that the signature is valid for the aggregate key given the
// message digest.
if !sig.Verify(dataHash.CloneBytes(), aggKey.FinalKey) {
return fmt.Errorf("invalid sig")
}

return nil
}

// chanAnn2P2WSHMuSig2Keys returns the set of keys that should be used to
// construct the aggregate key that the signature in an
// lnwire.ChannelAnnouncement2 message should be verified against in the case
// where the channel being announced is a P2WSH channel.
func chanAnn2P2WSHMuSig2Keys(a *lnwire.ChannelAnnouncement2) (
[]*btcec.PublicKey, error) {

nodeKey1, err := btcec.ParsePubKey(a.NodeID1.Val[:])
if err != nil {
return err
return nil, err
}

nodeKey2, err := btcec.ParsePubKey(a.NodeID2.Val[:])
if err != nil {
return err
return nil, err
}

btcKeyMissingErrString := "bitcoin key %d missing for announcement " +
"of a P2WSH channel"

btcKey1Bytes, err := a.BitcoinKey1.UnwrapOrErr(
fmt.Errorf(btcKeyMissingErrString, 1),
)
if err != nil {
return nil, err
}

btcKey1, err := btcec.ParsePubKey(btcKey1Bytes.Val[:])
if err != nil {
return nil, err
}

btcKey2Bytes, err := a.BitcoinKey2.UnwrapOrErr(
fmt.Errorf(btcKeyMissingErrString, 2),
)
if err != nil {
return nil, err
}

btcKey2, err := btcec.ParsePubKey(btcKey2Bytes.Val[:])
if err != nil {
return nil, err
}

return []*btcec.PublicKey{
nodeKey1, nodeKey2, btcKey1, btcKey2,
}, nil
}

// chanAnn2P2TRMuSig2Keys returns the set of keys that should be used to
// construct the aggregate key that the signature in an
// lnwire.ChannelAnnouncement2 message should be verified against in the case
// where the channel being announced is a P2TR channel.
func chanAnn2P2TRMuSig2Keys(a *lnwire.ChannelAnnouncement2,
scriptAddr btcutil.Address) ([]*btcec.PublicKey, error) {

nodeKey1, err := btcec.ParsePubKey(a.NodeID1.Val[:])
if err != nil {
return nil, err
}

nodeKey2, err := btcec.ParsePubKey(a.NodeID2.Val[:])
if err != nil {
return nil, err
}

keys := []*btcec.PublicKey{
Expand All @@ -240,42 +343,29 @@ func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,

bitcoinKey1, err := btcec.ParsePubKey(btcKey1.Val[:])
if err != nil {
return err
return nil, err
}

bitcoinKey2, err := btcec.ParsePubKey(btcKey2.Val[:])
if err != nil {
return err
return nil, err
}

keys = append(keys, bitcoinKey1, bitcoinKey2)
} else {
// If bitcoin keys are not provided, then we need to get the
// on-chain output key since this will be the 3rd key in the
// 3-of-3 MuSig2 signature.
pkScript, err := fetchPkScript(&a.ShortChannelID.Val)
if err != nil {
return err
}

outputKey, err := schnorr.ParsePubKey(pkScript[2:])
// If bitcoin keys are not provided, then the on-chain output
// key is considered the 3rd key in the 3-of-3 MuSig2 signature.
outputKey, err := schnorr.ParsePubKey(
scriptAddr.ScriptAddress(),
)
if err != nil {
return err
return nil, err
}

keys = append(keys, outputKey)
}

aggKey, _, _, err := musig2.AggregateKeys(keys, true)
if err != nil {
return err
}

if !sig.Verify(dataHash.CloneBytes(), aggKey.FinalKey) {
return fmt.Errorf("invalid sig")
}

return nil
return keys, nil
}

// ChanAnn2DigestToSign computes the digest of the message to be signed.
Expand Down
Loading
Loading