Skip to content

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

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

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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: 36 additions & 18 deletions discovery/gossiper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,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 @@ -192,14 +194,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
Expand Down Expand Up @@ -574,7 +571,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper
gossiper.vb = NewValidationBarrier(1000, gossiper.quit)

gossiper.syncMgr = newSyncManager(&SyncManagerCfg{
ChainHash: cfg.ChainHash,
ChainHash: *cfg.ChainParams.GenesisHash,
ChanSeries: cfg.ChanSeries,
RotateTicker: cfg.RotateTicker,
HistoricalSyncTicker: cfg.HistoricalSyncTicker,
Expand Down Expand Up @@ -1992,10 +1989,29 @@ func (d *AuthenticatedGossiper) processRejectedEdge(
}

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

return lnwallet.FetchPKScriptWithQuit(d.cfg.ChainIO, chanID, d.quit)
pkScript, err := lnwallet.FetchPKScriptWithQuit(
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 scriptClass, addrs[0], nil
}

// addNode processes the given node announcement, and adds it to our channel
Expand Down Expand Up @@ -2482,16 +2498,16 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
ops ...batch.SchedulerOption) ([]networkMsg, bool) {

scid := ann.ShortChannelID
chainHash := d.cfg.ChainParams.GenesisHash

log.Debugf("Processing ChannelAnnouncement1: peer=%v, short_chan_id=%v",
nMsg.peer, scid.ToUint64())

// 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[:], chainHash[:]) {
err := fmt.Errorf("ignoring ChannelAnnouncement1 from chain=%v"+
", gossiper on chain=%v", ann.ChainHash,
d.cfg.ChainHash)
", gossiper on chain=%v", ann.ChainHash, chainHash)
log.Errorf(err.Error())

key := newRejectCacheKey(
Expand Down Expand Up @@ -2942,11 +2958,13 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
log.Debugf("Processing ChannelUpdate: peer=%v, short_chan_id=%v, ",
nMsg.peer, upd.ShortChannelID.ToUint64())

chainHash := d.cfg.ChainParams.GenesisHash

// 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[:], chainHash[:]) {
err := fmt.Errorf("ignoring ChannelUpdate from chain=%v, "+
"gossiper on chain=%v", upd.ChainHash, d.cfg.ChainHash)
"gossiper on chain=%v", upd.ChainHash, chainHash)
log.Errorf(err.Error())

key := newRejectCacheKey(
Expand Down Expand Up @@ -3700,7 +3718,7 @@ func (d *AuthenticatedGossiper) validateFundingTransaction(
// Before we can add the channel to the channel graph, we need to obtain
// the full funding outpoint that's encoded within the channel ID.
fundingTx, err := lnwallet.FetchFundingTxWrapper(
d.cfg.ChainIO, &scid, d.quit,
d.cfg.ChainIO, scid, d.quit,
)
if err != nil {
//nolint:ll
Expand Down
9 changes: 7 additions & 2 deletions 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 @@ -616,6 +617,7 @@ func createUpdateAnnouncement(blockHeight uint32,

htlcMinMsat := lnwire.MilliSatoshi(100)
a := &lnwire.ChannelUpdate1{
ChainHash: *chaincfg.MainNetParams.GenesisHash,
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
},
Expand Down Expand Up @@ -768,6 +770,7 @@ func (ctx *testCtx) createAnnouncementWithoutProof(blockHeight uint32,
}

a := &lnwire.ChannelAnnouncement1{
ChainHash: *chaincfg.MainNetParams.GenesisHash,
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
TxIndex: 0,
Expand Down Expand Up @@ -934,8 +937,9 @@ func createTestCtx(t *testing.T, startHeight uint32, isChanPeer bool) (
}

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

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

//nolint:ll
gossiper := New(Config{
ChainParams: &chaincfg.MainNetParams,
Notifier: ctx.gossiper.cfg.Notifier,
Broadcast: ctx.gossiper.cfg.Broadcast,
NotifyWhenOnline: ctx.gossiper.reliableSender.cfg.NotifyWhenOnline,
Expand Down
8 changes: 4 additions & 4 deletions lnwallet/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ func SupportedWallets() []string {

// FetchFundingTxWrapper is a wrapper around FetchFundingTx, except that it will
// exit when the supplied quit channel is closed.
func FetchFundingTxWrapper(chain BlockChainIO, chanID *lnwire.ShortChannelID,
func FetchFundingTxWrapper(chain BlockChainIO, chanID lnwire.ShortChannelID,
quit chan struct{}) (*wire.MsgTx, error) {

txChan := make(chan *wire.MsgTx, 1)
Expand Down Expand Up @@ -789,7 +789,7 @@ func FetchFundingTxWrapper(chain BlockChainIO, chanID *lnwire.ShortChannelID,
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
// later use getblocktxn).
func FetchFundingTx(chain BlockChainIO,
chanID *lnwire.ShortChannelID) (*wire.MsgTx, error) {
chanID lnwire.ShortChannelID) (*wire.MsgTx, error) {

// First fetch the block hash by the block number encoded, then use
// that hash to fetch the block itself.
Expand Down Expand Up @@ -820,7 +820,7 @@ func FetchFundingTx(chain BlockChainIO,
// FetchPKScriptWithQuit fetches the output script for the given SCID and exits
// early with an error if the provided quit channel is closed before
// completion.
func FetchPKScriptWithQuit(chain BlockChainIO, chanID *lnwire.ShortChannelID,
func FetchPKScriptWithQuit(chain BlockChainIO, chanID lnwire.ShortChannelID,
quit chan struct{}) ([]byte, error) {

tx, err := FetchFundingTxWrapper(chain, chanID, quit)
Expand All @@ -829,7 +829,7 @@ func FetchPKScriptWithQuit(chain BlockChainIO, chanID *lnwire.ShortChannelID,
}

outputLocator := chanvalidate.ShortChanIDChanLocator{
ID: *chanID,
ID: chanID,
}

output, _, err := outputLocator.Locate(tx)
Expand Down
94 changes: 62 additions & 32 deletions lnwire/announcement_signatures_2.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package lnwire
import (
"bytes"
"io"

"github.com/lightningnetwork/lnd/tlv"
)

// AnnounceSignatures2 is a direct message between two endpoints of a
Expand All @@ -14,27 +16,40 @@ type AnnounceSignatures2 struct {
// Channel id is better for users and debugging and short channel id is
// used for quick test on existence of the particular utxo inside the
// blockchain, because it contains information about block.
ChannelID ChannelID
ChannelID tlv.RecordT[tlv.TlvType0, ChannelID]

// ShortChannelID is the unique description of the funding transaction.
// It is constructed with the most significant 3 bytes as the block
// height, the next 3 bytes indicating the transaction index within the
// block, and the least significant two bytes indicating the output
// index which pays to the channel.
ShortChannelID ShortChannelID
ShortChannelID tlv.RecordT[tlv.TlvType2, ShortChannelID]

// PartialSignature is the combination of the partial Schnorr signature
// created for the node's bitcoin key with the partial signature created
// for the node's node ID key.
PartialSignature PartialSig

// ExtraOpaqueData is the set of data that was appended to this
// message, some of which we may not actually know how to iterate or
// parse. By holding onto this data, we ensure that we're able to
// properly validate the set of signatures that cover these new fields,
// and ensure we're able to make upgrades to the network in a forwards
// compatible manner.
ExtraOpaqueData ExtraOpaqueData
PartialSignature tlv.RecordT[tlv.TlvType4, PartialSig]

// Any extra fields in the signed range that we do not yet know about,
// but we need to keep them for signature validation and to produce a
// valid message.
ExtraSignedFields
}

// NewAnnSigs2 is a constructor for AnnounceSignatures2.
func NewAnnSigs2(chanID ChannelID, scid ShortChannelID,
partialSig PartialSig) *AnnounceSignatures2 {

return &AnnounceSignatures2{
ChannelID: tlv.NewRecordT[tlv.TlvType0, ChannelID](chanID),
ShortChannelID: tlv.NewRecordT[tlv.TlvType2, ShortChannelID](
scid,
),
PartialSignature: tlv.NewRecordT[tlv.TlvType4, PartialSig](
partialSig,
),
ExtraSignedFields: make(ExtraSignedFields),
}
}

// A compile time check to ensure AnnounceSignatures2 implements the
Expand All @@ -50,32 +65,29 @@ var _ SizeableMessage = (*AnnounceSignatures2)(nil)
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures2) Decode(r io.Reader, _ uint32) error {
return ReadElements(r,
&a.ChannelID,
&a.ShortChannelID,
&a.PartialSignature,
&a.ExtraOpaqueData,
)
}

// Encode serializes the target AnnounceSignatures2 into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures2) Encode(w *bytes.Buffer, _ uint32) error {
if err := WriteChannelID(w, a.ChannelID); err != nil {
stream, err := tlv.NewStream(ProduceRecordsSorted(
&a.ChannelID, &a.ShortChannelID, &a.PartialSignature,
)...)
if err != nil {
return err
}

if err := WriteShortChannelID(w, a.ShortChannelID); err != nil {
typeMap, err := stream.DecodeWithParsedTypesP2P(r)
if err != nil {
return err
}

if err := WriteElement(w, a.PartialSignature); err != nil {
return err
}
a.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)

return WriteBytes(w, a.ExtraOpaqueData)
return nil
}

// Encode serializes the target AnnounceSignatures2 into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures2) Encode(w *bytes.Buffer, _ uint32) error {
return EncodePureTLVMessage(a, w)
}

// MsgType returns the integer uniquely identifying this message type on the
Expand All @@ -93,16 +105,34 @@ func (a *AnnounceSignatures2) SerializedSize() (uint32, error) {
return MessageSerializedSize(a)
}

// AllRecords returns all the TLV records for the message. This will include all
// the records we know about along with any that we don't know about but that
// fall in the signed TLV range.
//
// NOTE: this is part of the PureTLVMessage interface.
func (a *AnnounceSignatures2) AllRecords() []tlv.Record {
recordProducers := []tlv.RecordProducer{
&a.ChannelID, &a.ShortChannelID,
&a.PartialSignature,
}

recordProducers = append(recordProducers, RecordsAsProducers(
tlv.MapToRecords(a.ExtraSignedFields),
)...)

return ProduceRecordsSorted(recordProducers...)
}

// SCID returns the ShortChannelID of the channel.
//
// NOTE: this is part of the AnnounceSignatures interface.
func (a *AnnounceSignatures2) SCID() ShortChannelID {
return a.ShortChannelID
return a.ShortChannelID.Val
}

// ChanID returns the ChannelID identifying the channel.
//
// NOTE: this is part of the AnnounceSignatures interface.
func (a *AnnounceSignatures2) ChanID() ChannelID {
return a.ChannelID
return a.ChannelID.Val
}
Loading
Loading