-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
20db079
de6061e
321083c
df034bc
7483ed7
22293d5
6f0ce3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
|
@@ -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 | ||
|
||
// Graph is the subsystem which is responsible for managing the | ||
// topology of lightning network. After incoming channel, node, channel | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need it here if we have |
||
} | ||
|
||
// processedNetworkMsg is a wrapper around networkMsg and a boolean. It is | ||
|
@@ -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, | ||
|
@@ -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, | ||
|
@@ -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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -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( | ||
|
@@ -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( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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, | ||
|
@@ -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{ | ||
|
@@ -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. | ||
|
There was a problem hiding this comment.
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.