Merge pull request #8044 from ellemouton/g175Messages

[1/7] lnwire: add new Gossip 1.75 messages
This commit is contained in:
Olaoluwa Osuntokun 2024-09-18 16:05:38 -07:00 committed by GitHub
commit 13a7becb91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 2617 additions and 556 deletions

View file

@ -191,14 +191,16 @@ type WaitingProofKey [9]byte
// needed to make channel proof exchange persistent, so that after client
// restart we may receive remote/local half proof and process it.
type WaitingProof struct {
*lnwire.AnnounceSignatures
*lnwire.AnnounceSignatures1
isRemote bool
}
// NewWaitingProof constructs a new waiting prof instance.
func NewWaitingProof(isRemote bool, proof *lnwire.AnnounceSignatures) *WaitingProof {
func NewWaitingProof(isRemote bool,
proof *lnwire.AnnounceSignatures1) *WaitingProof {
return &WaitingProof{
AnnounceSignatures: proof,
AnnounceSignatures1: proof,
isRemote: isRemote,
}
}
@ -238,7 +240,7 @@ func (p *WaitingProof) Encode(w io.Writer) error {
return fmt.Errorf("expect io.Writer to be *bytes.Buffer")
}
if err := p.AnnounceSignatures.Encode(buf, 0); err != nil {
if err := p.AnnounceSignatures1.Encode(buf, 0); err != nil {
return err
}
@ -252,11 +254,12 @@ func (p *WaitingProof) Decode(r io.Reader) error {
return err
}
msg := &lnwire.AnnounceSignatures{}
msg := &lnwire.AnnounceSignatures1{}
if err := msg.Decode(r, 0); err != nil {
return err
}
(*p).AnnounceSignatures = msg
p.AnnounceSignatures1 = msg
return nil
}

View file

@ -18,7 +18,7 @@ func TestWaitingProofStore(t *testing.T) {
db, err := MakeTestDB(t)
require.NoError(t, err, "failed to make test database")
proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures{
proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures1{
NodeSignature: wireSig,
BitcoinSignature: wireSig,
ExtraOpaqueData: make([]byte, 0),

View file

@ -5,7 +5,6 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/graph"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/routing/route"
@ -61,7 +60,8 @@ type ChannelGraphTimeSeries interface {
// specified short channel ID. If no channel updates are known for the
// channel, then an empty slice will be returned.
FetchChanUpdates(chain chainhash.Hash,
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error)
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1,
error)
}
// ChanSeries is an implementation of the ChannelGraphTimeSeries
@ -136,7 +136,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
if edge1 != nil {
// We don't want to send channel updates that don't
// conform to the spec (anymore).
err := graph.ValidateChannelUpdateFields(0, edge1)
err := netann.ValidateChannelUpdateFields(0, edge1)
if err != nil {
log.Errorf("not sending invalid channel "+
"update %v: %v", edge1, err)
@ -145,7 +145,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
}
}
if edge2 != nil {
err := graph.ValidateChannelUpdateFields(0, edge2)
err := netann.ValidateChannelUpdateFields(0, edge2)
if err != nil {
log.Errorf("not sending invalid channel "+
"update %v: %v", edge2, err)
@ -326,7 +326,7 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
//
// NOTE: This is part of the ChannelGraphTimeSeries interface.
func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash,
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) {
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, error) {
chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID(
shortChanID.ToUint64(),
@ -335,7 +335,7 @@ func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash,
return nil, err
}
chanUpdates := make([]*lnwire.ChannelUpdate, 0, 2)
chanUpdates := make([]*lnwire.ChannelUpdate1, 0, 2)
if e1 != nil {
chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e1)
if err != nil {

View file

@ -171,6 +171,10 @@ type Config struct {
// order to be included in the LN graph.
Graph graph.ChannelGraphSource
// ChainIO represents an abstraction over a source that can query the
// blockchain.
ChainIO lnwallet.BlockChainIO
// ChanSeries is an interfaces that provides access to a time series
// view of the current known channel graph. Each GossipSyncer enabled
// peer will utilize this in order to create and respond to channel
@ -322,7 +326,7 @@ type Config struct {
// SignAliasUpdate is used to re-sign a channel update using the
// remote's alias if the option-scid-alias feature bit was negotiated.
SignAliasUpdate func(u *lnwire.ChannelUpdate) (*ecdsa.Signature,
SignAliasUpdate func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
error)
// FindBaseByAlias finds the SCID stored in the graph by an alias SCID.
@ -849,9 +853,9 @@ func (d *AuthenticatedGossiper) ProcessRemoteAnnouncement(msg lnwire.Message,
// To avoid inserting edges in the graph for our own channels that we
// have already closed, we ignore such channel announcements coming
// from the remote.
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
ownKey := d.selfKey.SerializeCompressed()
ownErr := fmt.Errorf("ignoring remote ChannelAnnouncement " +
ownErr := fmt.Errorf("ignoring remote ChannelAnnouncement1 " +
"for own channel")
if bytes.Equal(m.NodeID1[:], ownKey) ||
@ -1011,7 +1015,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
switch msg := message.msg.(type) {
// Channel announcements are identified by the short channel id field.
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
deDupKey := msg.ShortChannelID
sender := route.NewVertex(message.source)
@ -1035,7 +1039,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
// Channel updates are identified by the (short channel id,
// channelflags) tuple.
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
sender := route.NewVertex(message.source)
deDupKey := channelUpdateID{
msg.ShortChannelID,
@ -1047,7 +1051,15 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
if ok {
// If we already have seen this message, record its
// timestamp.
oldTimestamp = mws.msg.(*lnwire.ChannelUpdate).Timestamp
update, ok := mws.msg.(*lnwire.ChannelUpdate1)
if !ok {
log.Errorf("Expected *lnwire.ChannelUpdate1, "+
"got: %T", mws.msg)
return
}
oldTimestamp = update.Timestamp
}
// If we already had this message with a strictly newer
@ -1416,7 +1428,7 @@ func (d *AuthenticatedGossiper) networkHandler() {
switch announcement.msg.(type) {
// Channel announcement signatures are amongst the only
// messages that we'll process serially.
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
emittedAnnouncements, _ := d.processNetworkAnnouncement(
announcement,
)
@ -1582,10 +1594,10 @@ func (d *AuthenticatedGossiper) isRecentlyRejectedMsg(msg lnwire.Message,
var scid uint64
switch m := msg.(type) {
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
scid = m.ShortChannelID.ToUint64()
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
scid = m.ShortChannelID.ToUint64()
default:
@ -1844,7 +1856,7 @@ func remotePubFromChanInfo(chanInfo *models.ChannelEdgeInfo,
// to receive the remote peer's proof, while the remote peer is able to fully
// assemble the proof and craft the ChannelAnnouncement.
func (d *AuthenticatedGossiper) processRejectedEdge(
chanAnnMsg *lnwire.ChannelAnnouncement,
chanAnnMsg *lnwire.ChannelAnnouncement1,
proof *models.ChannelAuthProof) ([]networkMsg, error) {
// First, we'll fetch the state of the channel as we know if from the
@ -1878,7 +1890,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge(
if err != nil {
return nil, err
}
err = graph.ValidateChannelAnn(chanAnn)
err = netann.ValidateChannelAnn(chanAnn, d.fetchPKScript)
if err != nil {
err := fmt.Errorf("assembled channel announcement proof "+
"for shortChanID=%v isn't valid: %v",
@ -1922,6 +1934,13 @@ func (d *AuthenticatedGossiper) processRejectedEdge(
return announcements, nil
}
// fetchPKScript fetches the output script for the given SCID.
func (d *AuthenticatedGossiper) fetchPKScript(chanID *lnwire.ShortChannelID) (
[]byte, error) {
return lnwallet.FetchPKScriptWithQuit(d.cfg.ChainIO, chanID, d.quit)
}
// addNode processes the given node announcement, and adds it to our channel
// graph.
func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
@ -2029,19 +2048,19 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// *creation* of a new channel within the network. This only advertises
// the existence of a channel and not yet the routing policies in
// either direction of the channel.
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
return d.handleChanAnnouncement(nMsg, msg, schedulerOp)
// A new authenticated channel edge update has arrived. This indicates
// that the directional information for an already known channel has
// been updated.
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
return d.handleChanUpdate(nMsg, msg, schedulerOp)
// A new signature announcement has been received. This indicates
// willingness of nodes involved in the funding of a channel to
// announce this new channel to the rest of the world.
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
return d.handleAnnSig(nMsg, msg)
default:
@ -2058,7 +2077,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// should be inspected.
func (d *AuthenticatedGossiper) processZombieUpdate(
chanInfo *models.ChannelEdgeInfo, scid lnwire.ShortChannelID,
msg *lnwire.ChannelUpdate) error {
msg *lnwire.ChannelUpdate1) error {
// The least-significant bit in the flag on the channel update tells us
// which edge is being updated.
@ -2081,7 +2100,7 @@ func (d *AuthenticatedGossiper) processZombieUpdate(
"with chan_id=%v", msg.ShortChannelID)
}
err := graph.VerifyChannelUpdateSignature(msg, pubKey)
err := netann.VerifyChannelUpdateSignature(msg, pubKey)
if err != nil {
return fmt.Errorf("unable to verify channel "+
"update signature: %v", err)
@ -2129,7 +2148,7 @@ func (d *AuthenticatedGossiper) fetchNodeAnn(
// MessageStore is seen as stale by the current graph.
func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool {
switch msg := msg.(type) {
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
chanInfo, _, _, err := d.cfg.Graph.GetChannelByID(
msg.ShortChannelID,
)
@ -2151,7 +2170,7 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool {
// can safely delete the local proof from the database.
return chanInfo.AuthProof != nil
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
_, p1, p2, err := d.cfg.Graph.GetChannelByID(msg.ShortChannelID)
// If the channel cannot be found, it is most likely a leftover
@ -2195,8 +2214,8 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool {
// updateChannel creates a new fully signed update for the channel, and updates
// the underlying graph with the new state.
func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo,
edge *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement,
*lnwire.ChannelUpdate, error) {
edge *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1,
*lnwire.ChannelUpdate1, error) {
// Parse the unsigned edge into a channel update.
chanUpdate := netann.UnsignedChannelUpdateFromEdge(info, edge)
@ -2218,7 +2237,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo,
// To ensure that our signature is valid, we'll verify it ourself
// before committing it to the slice returned.
err = graph.ValidateChannelUpdateAnn(
err = netann.ValidateChannelUpdateAnn(
d.selfKey, info.Capacity, chanUpdate,
)
if err != nil {
@ -2234,10 +2253,10 @@ func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo,
// We'll also create the original channel announcement so the two can
// be broadcast along side each other (if necessary), but only if we
// have a full channel announcement for this channel.
var chanAnn *lnwire.ChannelAnnouncement
var chanAnn *lnwire.ChannelAnnouncement1
if info.AuthProof != nil {
chanID := lnwire.NewShortChanIDFromInt(info.ChannelID)
chanAnn = &lnwire.ChannelAnnouncement{
chanAnn = &lnwire.ChannelAnnouncement1{
ShortChannelID: chanID,
NodeID1: info.NodeKey1Bytes,
NodeID2: info.NodeKey2Bytes,
@ -2284,7 +2303,7 @@ func (d *AuthenticatedGossiper) SyncManager() *SyncManager {
// IsKeepAliveUpdate determines whether this channel update is considered a
// keep-alive update based on the previous channel update processed for the same
// direction.
func IsKeepAliveUpdate(update *lnwire.ChannelUpdate,
func IsKeepAliveUpdate(update *lnwire.ChannelUpdate1,
prev *models.ChannelEdgePolicy) bool {
// Both updates should be from the same direction.
@ -2409,18 +2428,18 @@ func (d *AuthenticatedGossiper) handleNodeAnnouncement(nMsg *networkMsg,
// handleChanAnnouncement processes a new channel announcement.
func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
ann *lnwire.ChannelAnnouncement,
ann *lnwire.ChannelAnnouncement1,
ops []batch.SchedulerOption) ([]networkMsg, bool) {
scid := ann.ShortChannelID
log.Debugf("Processing ChannelAnnouncement: peer=%v, short_chan_id=%v",
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[:]) {
err := fmt.Errorf("ignoring ChannelAnnouncement from chain=%v"+
err := fmt.Errorf("ignoring ChannelAnnouncement1 from chain=%v"+
", gossiper on chain=%v", ann.ChainHash,
d.cfg.ChainHash)
log.Errorf(err.Error())
@ -2521,7 +2540,8 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
// the signatures within the proof as it should be well formed.
var proof *models.ChannelAuthProof
if nMsg.isRemote {
if err := graph.ValidateChannelAnn(ann); err != nil {
err := netann.ValidateChannelAnn(ann, d.fetchPKScript)
if err != nil {
err := fmt.Errorf("unable to validate announcement: "+
"%v", err)
@ -2753,7 +2773,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
// Reprocess the message, making sure we return an
// error to the original caller in case the gossiper
// shuts down.
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
log.Debugf("Reprocessing ChannelUpdate for "+
"shortChanID=%v", scid.ToUint64())
@ -2788,7 +2808,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
nMsg.err <- nil
log.Debugf("Processed ChannelAnnouncement: peer=%v, short_chan_id=%v",
log.Debugf("Processed ChannelAnnouncement1: peer=%v, short_chan_id=%v",
nMsg.peer, scid.ToUint64())
return announcements, true
@ -2796,7 +2816,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
// handleChanUpdate processes a new channel update.
func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
upd *lnwire.ChannelUpdate,
upd *lnwire.ChannelUpdate1,
ops []batch.SchedulerOption) ([]networkMsg, bool) {
log.Debugf("Processing ChannelUpdate: peer=%v, short_chan_id=%v, ",
@ -3009,7 +3029,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
// Validate the channel announcement with the expected public key and
// channel capacity. In the case of an invalid channel update, we'll
// return an error to the caller and exit early.
err = graph.ValidateChannelUpdateAnn(pubKey, chanInfo.Capacity, upd)
err = netann.ValidateChannelUpdateAnn(pubKey, chanInfo.Capacity, upd)
if err != nil {
rErr := fmt.Errorf("unable to validate channel update "+
"announcement for short_chan_id=%v: %v",
@ -3200,7 +3220,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
// handleAnnSig processes a new announcement signatures message.
func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg,
ann *lnwire.AnnounceSignatures) ([]networkMsg, bool) {
ann *lnwire.AnnounceSignatures1) ([]networkMsg, bool) {
needBlockHeight := ann.ShortChannelID.BlockHeight +
d.cfg.ProofMatureDelta
@ -3415,7 +3435,8 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg,
// With all the necessary components assembled validate the full
// channel announcement proof.
if err := graph.ValidateChannelAnn(chanAnn); err != nil {
err = netann.ValidateChannelAnn(chanAnn, d.fetchPKScript)
if err != nil {
err := fmt.Errorf("channel announcement proof for "+
"short_chan_id=%v isn't valid: %v", shortChanID, err)

View file

@ -476,13 +476,13 @@ type annBatch struct {
nodeAnn1 *lnwire.NodeAnnouncement
nodeAnn2 *lnwire.NodeAnnouncement
chanAnn *lnwire.ChannelAnnouncement
chanAnn *lnwire.ChannelAnnouncement1
chanUpdAnn1 *lnwire.ChannelUpdate
chanUpdAnn2 *lnwire.ChannelUpdate
chanUpdAnn1 *lnwire.ChannelUpdate1
chanUpdAnn2 *lnwire.ChannelUpdate1
localProofAnn *lnwire.AnnounceSignatures
remoteProofAnn *lnwire.AnnounceSignatures
localProofAnn *lnwire.AnnounceSignatures1
remoteProofAnn *lnwire.AnnounceSignatures1
}
func createLocalAnnouncements(blockHeight uint32) (*annBatch, error) {
@ -513,7 +513,7 @@ func createAnnouncements(blockHeight uint32, key1, key2 *btcec.PrivateKey) (*ann
return nil, err
}
batch.remoteProofAnn = &lnwire.AnnounceSignatures{
batch.remoteProofAnn = &lnwire.AnnounceSignatures1{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
},
@ -521,7 +521,7 @@ func createAnnouncements(blockHeight uint32, key1, key2 *btcec.PrivateKey) (*ann
BitcoinSignature: batch.chanAnn.BitcoinSig2,
}
batch.localProofAnn = &lnwire.AnnounceSignatures{
batch.localProofAnn = &lnwire.AnnounceSignatures1{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
},
@ -585,12 +585,12 @@ func createNodeAnnouncement(priv *btcec.PrivateKey,
func createUpdateAnnouncement(blockHeight uint32,
flags lnwire.ChanUpdateChanFlags,
nodeKey *btcec.PrivateKey, timestamp uint32,
extraBytes ...[]byte) (*lnwire.ChannelUpdate, error) {
extraBytes ...[]byte) (*lnwire.ChannelUpdate1, error) {
var err error
htlcMinMsat := lnwire.MilliSatoshi(prand.Int63())
a := &lnwire.ChannelUpdate{
a := &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
},
@ -618,7 +618,7 @@ func createUpdateAnnouncement(blockHeight uint32,
return a, nil
}
func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error {
func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate1) error {
signer := mock.SingleSigner{Privkey: nodeKey}
sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil {
@ -635,9 +635,9 @@ func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error {
func createAnnouncementWithoutProof(blockHeight uint32,
key1, key2 *btcec.PublicKey,
extraBytes ...[]byte) *lnwire.ChannelAnnouncement {
extraBytes ...[]byte) *lnwire.ChannelAnnouncement1 {
a := &lnwire.ChannelAnnouncement{
a := &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: blockHeight,
TxIndex: 0,
@ -657,13 +657,13 @@ func createAnnouncementWithoutProof(blockHeight uint32,
}
func createRemoteChannelAnnouncement(blockHeight uint32,
extraBytes ...[]byte) (*lnwire.ChannelAnnouncement, error) {
extraBytes ...[]byte) (*lnwire.ChannelAnnouncement1, error) {
return createChannelAnnouncement(blockHeight, remoteKeyPriv1, remoteKeyPriv2, extraBytes...)
}
func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
extraBytes ...[]byte) (*lnwire.ChannelAnnouncement, error) {
extraBytes ...[]byte) (*lnwire.ChannelAnnouncement1, error) {
a := createAnnouncementWithoutProof(blockHeight, key1.PubKey(), key2.PubKey(), extraBytes...)
@ -749,7 +749,7 @@ func createTestCtx(t *testing.T, startHeight uint32, isChanPeer bool) (
return false
}
signAliasUpdate := func(*lnwire.ChannelUpdate) (*ecdsa.Signature,
signAliasUpdate := func(*lnwire.ChannelUpdate1) (*ecdsa.Signature,
error) {
return nil, nil
@ -1462,7 +1462,7 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
return false
}
signAliasUpdate := func(*lnwire.ChannelUpdate) (*ecdsa.Signature,
signAliasUpdate := func(*lnwire.ChannelUpdate1) (*ecdsa.Signature,
error) {
return nil, nil
@ -1540,7 +1540,7 @@ out:
case msg := <-sentToPeer:
// Since the ChannelUpdate will also be resent as it is
// sent reliably, we'll need to filter it out.
if _, ok := msg.(*lnwire.AnnounceSignatures); !ok {
if _, ok := msg.(*lnwire.AnnounceSignatures1); !ok {
continue
}
@ -1768,9 +1768,10 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
// We expect the gossiper to send this message to the remote peer.
select {
case msg := <-sentToPeer:
_, ok := msg.(*lnwire.ChannelAnnouncement)
_, ok := msg.(*lnwire.ChannelAnnouncement1)
if !ok {
t.Fatalf("expected ChannelAnnouncement, instead got %T", msg)
t.Fatalf("expected ChannelAnnouncement1, instead got "+
"%T", msg)
}
case <-time.After(2 * time.Second):
t.Fatal("did not send local proof to peer")
@ -1867,7 +1868,7 @@ func TestDeDuplicatedAnnouncements(t *testing.T) {
t.Fatal("channel update not replaced in batch")
}
assertChannelUpdate := func(channelUpdate *lnwire.ChannelUpdate) {
assertChannelUpdate := func(channelUpdate *lnwire.ChannelUpdate1) {
channelKey := channelUpdateID{
ua3.ShortChannelID,
ua3.ChannelFlags,
@ -2811,9 +2812,9 @@ func TestRetransmit(t *testing.T) {
var chanAnn, chanUpd, nodeAnn int
for _, msg := range anns {
switch msg.(type) {
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
chanAnn++
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
chanUpd++
case *lnwire.NodeAnnouncement:
nodeAnn++
@ -3246,7 +3247,7 @@ func TestSendChannelUpdateReliably(t *testing.T) {
// already been announced. We'll keep track of the old message that is
// now stale to use later on.
staleChannelUpdate := batch.chanUpdAnn1
newChannelUpdate := &lnwire.ChannelUpdate{}
newChannelUpdate := &lnwire.ChannelUpdate1{}
*newChannelUpdate = *staleChannelUpdate
newChannelUpdate.Timestamp++
if err := signUpdate(selfKeyPriv, newChannelUpdate); err != nil {
@ -3300,9 +3301,9 @@ func TestSendChannelUpdateReliably(t *testing.T) {
}
switch msg := msg.(type) {
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
assertMessage(t, staleChannelUpdate, msg)
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
assertMessage(t, batch.localProofAnn, msg)
default:
t.Fatalf("send unexpected %v message", msg.MsgType())
@ -3504,7 +3505,7 @@ out:
// being the channel our first private channel.
for i := 0; i < numChannels-1; i++ {
assertBroadcastMsg(t, ctx, func(msg lnwire.Message) error {
upd, ok := msg.(*lnwire.ChannelUpdate)
upd, ok := msg.(*lnwire.ChannelUpdate1)
if !ok {
return fmt.Errorf("channel update not "+
"broadcast, instead %T was", msg)
@ -3528,7 +3529,7 @@ out:
// remote peer via the reliable sender.
select {
case msg := <-sentMsgs:
upd, ok := msg.(*lnwire.ChannelUpdate)
upd, ok := msg.(*lnwire.ChannelUpdate1)
if !ok {
t.Fatalf("channel update not "+
"broadcast, instead %T was", msg)
@ -3552,7 +3553,7 @@ out:
for {
select {
case msg := <-ctx.broadcastedMessage:
if upd, ok := msg.msg.(*lnwire.ChannelUpdate); ok {
if upd, ok := msg.msg.(*lnwire.ChannelUpdate1); ok {
if upd.ShortChannelID == firstChanID {
t.Fatalf("chan update msg received: %v",
spew.Sdump(msg))
@ -3884,7 +3885,7 @@ func TestRateLimitChannelUpdates(t *testing.T) {
// We'll define a helper to assert whether updates should be rate
// limited or not depending on their contents.
assertRateLimit := func(update *lnwire.ChannelUpdate, peer lnpeer.Peer,
assertRateLimit := func(update *lnwire.ChannelUpdate1, peer lnpeer.Peer,
shouldRateLimit bool) {
t.Helper()

View file

@ -83,9 +83,9 @@ func NewMessageStore(db kvdb.Backend) (*MessageStore, error) {
func msgShortChanID(msg lnwire.Message) (lnwire.ShortChannelID, error) {
var shortChanID lnwire.ShortChannelID
switch msg := msg.(type) {
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
shortChanID = msg.ShortChannelID
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
shortChanID = msg.ShortChannelID
default:
return shortChanID, ErrUnsupportedMessage
@ -160,7 +160,7 @@ func (s *MessageStore) DeleteMessage(msg lnwire.Message,
// In the event that we're attempting to delete a ChannelUpdate
// from the store, we'll make sure that we're actually deleting
// the correct one as it can be overwritten.
if msg, ok := msg.(*lnwire.ChannelUpdate); ok {
if msg, ok := msg.(*lnwire.ChannelUpdate1); ok {
// Deleting a value from a bucket that doesn't exist
// acts as a NOP, so we'll return if a message doesn't
// exist under this key.
@ -176,7 +176,13 @@ func (s *MessageStore) DeleteMessage(msg lnwire.Message,
// If the timestamps don't match, then the update stored
// should be the latest one, so we'll avoid deleting it.
if msg.Timestamp != dbMsg.(*lnwire.ChannelUpdate).Timestamp {
m, ok := dbMsg.(*lnwire.ChannelUpdate1)
if !ok {
return fmt.Errorf("expected "+
"*lnwire.ChannelUpdate1, got: %T",
dbMsg)
}
if msg.Timestamp != m.Timestamp {
return nil
}
}

View file

@ -52,15 +52,15 @@ func randCompressedPubKey(t *testing.T) [33]byte {
return compressedPubKey
}
func randAnnounceSignatures() *lnwire.AnnounceSignatures {
return &lnwire.AnnounceSignatures{
func randAnnounceSignatures() *lnwire.AnnounceSignatures1 {
return &lnwire.AnnounceSignatures1{
ShortChannelID: lnwire.NewShortChanIDFromInt(rand.Uint64()),
ExtraOpaqueData: make([]byte, 0),
}
}
func randChannelUpdate() *lnwire.ChannelUpdate {
return &lnwire.ChannelUpdate{
func randChannelUpdate() *lnwire.ChannelUpdate1 {
return &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(rand.Uint64()),
ExtraOpaqueData: make([]byte, 0),
}
@ -116,9 +116,9 @@ func TestMessageStoreMessages(t *testing.T) {
for _, msg := range peerMsgs {
var shortChanID uint64
switch msg := msg.(type) {
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
shortChanID = msg.ShortChannelID.ToUint64()
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
shortChanID = msg.ShortChannelID.ToUint64()
default:
t.Fatalf("found unexpected message type %T", msg)

View file

@ -1406,9 +1406,11 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) {
// set of channel announcements and channel updates. This will allow us
// to quickly check if we should forward a chan ann, based on the known
// channel updates for a channel.
chanUpdateIndex := make(map[lnwire.ShortChannelID][]*lnwire.ChannelUpdate)
chanUpdateIndex := make(
map[lnwire.ShortChannelID][]*lnwire.ChannelUpdate1,
)
for _, msg := range msgs {
chanUpdate, ok := msg.msg.(*lnwire.ChannelUpdate)
chanUpdate, ok := msg.msg.(*lnwire.ChannelUpdate1)
if !ok {
continue
}
@ -1447,7 +1449,7 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) {
// For each channel announcement message, we'll only send this
// message if the channel updates for the channel are between
// our time range.
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
// First, we'll check if the channel updates are in
// this message batch.
chanUpdates, ok := chanUpdateIndex[msg.ShortChannelID]
@ -1478,7 +1480,7 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) {
// For each channel update, we'll only send if it the timestamp
// is between our time range.
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
if passesFilter(msg.Timestamp) {
msgsToSend = append(msgsToSend, msg)
}

View file

@ -52,7 +52,7 @@ type mockChannelGraphTimeSeries struct {
annResp chan []lnwire.Message
updateReq chan lnwire.ShortChannelID
updateResp chan []*lnwire.ChannelUpdate
updateResp chan []*lnwire.ChannelUpdate1
}
func newMockChannelGraphTimeSeries(
@ -74,7 +74,7 @@ func newMockChannelGraphTimeSeries(
annResp: make(chan []lnwire.Message, 1),
updateReq: make(chan lnwire.ShortChannelID, 1),
updateResp: make(chan []*lnwire.ChannelUpdate, 1),
updateResp: make(chan []*lnwire.ChannelUpdate1, 1),
}
}
@ -149,7 +149,7 @@ func (m *mockChannelGraphTimeSeries) FetchChanAnns(chain chainhash.Hash,
return <-m.annResp, nil
}
func (m *mockChannelGraphTimeSeries) FetchChanUpdates(chain chainhash.Hash,
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) {
shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, error) {
m.updateReq <- shortChanID
@ -306,36 +306,36 @@ func TestGossipSyncerFilterGossipMsgsAllInMemory(t *testing.T) {
},
{
// Ann tuple below horizon.
msg: &lnwire.ChannelAnnouncement{
msg: &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(10),
},
},
{
msg: &lnwire.ChannelUpdate{
msg: &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(10),
Timestamp: unixStamp(5),
},
},
{
// Ann tuple above horizon.
msg: &lnwire.ChannelAnnouncement{
msg: &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(15),
},
},
{
msg: &lnwire.ChannelUpdate{
msg: &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(15),
Timestamp: unixStamp(25002),
},
},
{
// Ann tuple beyond horizon.
msg: &lnwire.ChannelAnnouncement{
msg: &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(20),
},
},
{
msg: &lnwire.ChannelUpdate{
msg: &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(20),
Timestamp: unixStamp(999999),
},
@ -343,7 +343,7 @@ func TestGossipSyncerFilterGossipMsgsAllInMemory(t *testing.T) {
{
// Ann w/o an update at all, the update in the DB will
// be below the horizon.
msg: &lnwire.ChannelAnnouncement{
msg: &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(25),
},
},
@ -369,7 +369,7 @@ func TestGossipSyncerFilterGossipMsgsAllInMemory(t *testing.T) {
}
// If so, then we'll send back the missing update.
chanSeries.updateResp <- []*lnwire.ChannelUpdate{
chanSeries.updateResp <- []*lnwire.ChannelUpdate1{
{
ShortChannelID: lnwire.NewShortChanIDFromInt(25),
Timestamp: unixStamp(5),
@ -551,7 +551,7 @@ func TestGossipSyncerApplyGossipFilter(t *testing.T) {
// For this first response, we'll send back a proper
// set of messages that should be echoed back.
chanSeries.horizonResp <- []lnwire.Message{
&lnwire.ChannelUpdate{
&lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(25),
Timestamp: unixStamp(5),
},
@ -706,10 +706,10 @@ func TestGossipSyncerReplyShortChanIDs(t *testing.T) {
}
queryReply := []lnwire.Message{
&lnwire.ChannelAnnouncement{
&lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(20),
},
&lnwire.ChannelUpdate{
&lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(20),
Timestamp: unixStamp(999999),
},

View file

@ -52,6 +52,9 @@
# Technical and Architectural Updates
## BOLT Spec Updates
* Add new [lnwire](https://github.com/lightningnetwork/lnd/pull/8044) messages
for the Gossip 1.75 protocol.
## Testing
## Database

View file

@ -4143,9 +4143,9 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID,
// chanAnnouncement encapsulates the two authenticated announcements that we
// send out to the network after a new channel has been created locally.
type chanAnnouncement struct {
chanAnn *lnwire.ChannelAnnouncement
chanUpdateAnn *lnwire.ChannelUpdate
chanProof *lnwire.AnnounceSignatures
chanAnn *lnwire.ChannelAnnouncement1
chanUpdateAnn *lnwire.ChannelUpdate1
chanProof *lnwire.AnnounceSignatures1
}
// newChanAnnouncement creates the authenticated channel announcement messages
@ -4168,7 +4168,7 @@ func (f *Manager) newChanAnnouncement(localPubKey,
// The unconditional section of the announcement is the ShortChannelID
// itself which compactly encodes the location of the funding output
// within the blockchain.
chanAnn := &lnwire.ChannelAnnouncement{
chanAnn := &lnwire.ChannelAnnouncement1{
ShortChannelID: shortChanID,
Features: lnwire.NewRawFeatureVector(),
ChainHash: chainHash,
@ -4238,7 +4238,7 @@ func (f *Manager) newChanAnnouncement(localPubKey,
// We announce the channel with the default values. Some of
// these values can later be changed by crafting a new ChannelUpdate.
chanUpdateAnn := &lnwire.ChannelUpdate{
chanUpdateAnn := &lnwire.ChannelUpdate1{
ShortChannelID: shortChanID,
ChainHash: chainHash,
Timestamp: uint32(time.Now().Unix()),
@ -4337,7 +4337,7 @@ func (f *Manager) newChanAnnouncement(localPubKey,
// Finally, we'll generate the announcement proof which we'll use to
// provide the other side with the necessary signatures required to
// allow them to reconstruct the full channel announcement.
proof := &lnwire.AnnounceSignatures{
proof := &lnwire.AnnounceSignatures1{
ChannelID: chanID,
ShortChannelID: shortChanID,
}

View file

@ -1208,9 +1208,9 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode,
gotChannelUpdate := false
for _, msg := range announcements {
switch m := msg.(type) {
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
gotChannelAnnouncement = true
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
// The channel update sent by the node should
// advertise the MinHTLC value required by the
@ -1297,7 +1297,7 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) {
gotNodeAnnouncement := false
for _, msg := range announcements {
switch msg.(type) {
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
gotAnnounceSignatures = true
case *lnwire.NodeAnnouncement:
gotNodeAnnouncement = true

2
go.mod
View file

@ -45,6 +45,7 @@ require (
github.com/lightningnetwork/lnd/tor v1.1.2
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796
github.com/miekg/dns v1.1.43
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.1
github.com/stretchr/testify v1.9.0
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02
@ -135,7 +136,6 @@ require (
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/ory/dockertest/v3 v3.10.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.26.0 // indirect

View file

@ -2,89 +2,13 @@ package graph
import (
"bytes"
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/lnwire"
)
// ValidateChannelAnn validates the channel announcement message and checks
// that node signatures covers the announcement message, and that the bitcoin
// signatures covers the node keys.
func ValidateChannelAnn(a *lnwire.ChannelAnnouncement) error {
// First, we'll compute the digest (h) which is to be signed by each of
// the keys included within the node announcement message. This hash
// digest includes all the keys, so the (up to 4 signatures) will
// attest to the validity of each of the keys.
data, err := a.DataToSign()
if err != nil {
return err
}
dataHash := chainhash.DoubleHashB(data)
// First we'll verify that the passed bitcoin key signature is indeed a
// signature over the computed hash digest.
bitcoinSig1, err := a.BitcoinSig1.ToSignature()
if err != nil {
return err
}
bitcoinKey1, err := btcec.ParsePubKey(a.BitcoinKey1[:])
if err != nil {
return err
}
if !bitcoinSig1.Verify(dataHash, bitcoinKey1) {
return errors.New("can't verify first bitcoin signature")
}
// If that checks out, then we'll verify that the second bitcoin
// signature is a valid signature of the bitcoin public key over hash
// digest as well.
bitcoinSig2, err := a.BitcoinSig2.ToSignature()
if err != nil {
return err
}
bitcoinKey2, err := btcec.ParsePubKey(a.BitcoinKey2[:])
if err != nil {
return err
}
if !bitcoinSig2.Verify(dataHash, bitcoinKey2) {
return errors.New("can't verify second bitcoin signature")
}
// Both node signatures attached should indeed be a valid signature
// over the selected digest of the channel announcement signature.
nodeSig1, err := a.NodeSig1.ToSignature()
if err != nil {
return err
}
nodeKey1, err := btcec.ParsePubKey(a.NodeID1[:])
if err != nil {
return err
}
if !nodeSig1.Verify(dataHash, nodeKey1) {
return errors.New("can't verify data in first node signature")
}
nodeSig2, err := a.NodeSig2.ToSignature()
if err != nil {
return err
}
nodeKey2, err := btcec.ParsePubKey(a.NodeID2[:])
if err != nil {
return err
}
if !nodeSig2.Verify(dataHash, nodeKey2) {
return errors.New("can't verify data in second node signature")
}
return nil
}
// ValidateNodeAnn validates the node announcement by ensuring that the
// attached signature is needed a signature of the node announcement under the
// specified node public key.
@ -121,70 +45,3 @@ func ValidateNodeAnn(a *lnwire.NodeAnnouncement) error {
return nil
}
// ValidateChannelUpdateAnn validates the channel update announcement by
// checking (1) that the included signature covers the announcement and has been
// signed by the node's private key, and (2) that the announcement's message
// flags and optional fields are sane.
func ValidateChannelUpdateAnn(pubKey *btcec.PublicKey, capacity btcutil.Amount,
a *lnwire.ChannelUpdate) error {
if err := ValidateChannelUpdateFields(capacity, a); err != nil {
return err
}
return VerifyChannelUpdateSignature(a, pubKey)
}
// VerifyChannelUpdateSignature verifies that the channel update message was
// signed by the party with the given node public key.
func VerifyChannelUpdateSignature(msg *lnwire.ChannelUpdate,
pubKey *btcec.PublicKey) error {
data, err := msg.DataToSign()
if err != nil {
return fmt.Errorf("unable to reconstruct message data: %w", err)
}
dataHash := chainhash.DoubleHashB(data)
nodeSig, err := msg.Signature.ToSignature()
if err != nil {
return err
}
if !nodeSig.Verify(dataHash, pubKey) {
return fmt.Errorf("invalid signature for channel update %v",
spew.Sdump(msg))
}
return nil
}
// ValidateChannelUpdateFields validates a channel update's message flags and
// corresponding update fields.
func ValidateChannelUpdateFields(capacity btcutil.Amount,
msg *lnwire.ChannelUpdate) error {
// The maxHTLC flag is mandatory.
if !msg.MessageFlags.HasMaxHtlc() {
return errors.Errorf("max htlc flag not set for channel "+
"update %v", spew.Sdump(msg))
}
maxHtlc := msg.HtlcMaximumMsat
if maxHtlc == 0 || maxHtlc < msg.HtlcMinimumMsat {
return errors.Errorf("invalid max htlc for channel "+
"update %v", spew.Sdump(msg))
}
// For light clients, the capacity will not be set so we'll skip
// checking whether the MaxHTLC value respects the channel's
// capacity.
capacityMsat := lnwire.NewMSatFromSatoshis(capacity)
if capacityMsat != 0 && maxHtlc > capacityMsat {
return errors.Errorf("max_htlc (%v) for channel update "+
"greater than capacity (%v)", maxHtlc, capacityMsat)
}
return nil
}

View file

@ -27,6 +27,7 @@ import (
"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/multimutex"
"github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/routing/chainview"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/ticker"
@ -1231,7 +1232,9 @@ func (b *Builder) processUpdate(msg interface{},
// to obtain the full funding outpoint that's encoded within
// the channel ID.
channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
fundingTx, err := b.fetchFundingTxWrapper(&channelID)
fundingTx, err := lnwallet.FetchFundingTxWrapper(
b.cfg.Chain, &channelID, b.quit,
)
if err != nil {
//nolint:lll
//
@ -1448,69 +1451,6 @@ func (b *Builder) processUpdate(msg interface{},
return nil
}
// fetchFundingTxWrapper is a wrapper around fetchFundingTx, except that it
// will exit if the router has stopped.
func (b *Builder) fetchFundingTxWrapper(chanID *lnwire.ShortChannelID) (
*wire.MsgTx, error) {
txChan := make(chan *wire.MsgTx, 1)
errChan := make(chan error, 1)
go func() {
tx, err := b.fetchFundingTx(chanID)
if err != nil {
errChan <- err
return
}
txChan <- tx
}()
select {
case tx := <-txChan:
return tx, nil
case err := <-errChan:
return nil, err
case <-b.quit:
return nil, ErrGraphBuilderShuttingDown
}
}
// fetchFundingTx returns the funding transaction identified by the passed
// short channel ID.
//
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
// later use getblocktxn).
func (b *Builder) fetchFundingTx(
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.
blockNum := int64(chanID.BlockHeight)
blockHash, err := b.cfg.Chain.GetBlockHash(blockNum)
if err != nil {
return nil, err
}
fundingBlock, err := b.cfg.Chain.GetBlock(blockHash)
if err != nil {
return nil, err
}
// As a sanity check, ensure that the advertised transaction index is
// within the bounds of the total number of transactions within a
// block.
numTxns := uint32(len(fundingBlock.Transactions))
if chanID.TxIndex > numTxns-1 {
return nil, fmt.Errorf("tx_index=#%v "+
"is out of range (max_index=%v), network_chan_id=%v",
chanID.TxIndex, numTxns-1, chanID)
}
return fundingBlock.Transactions[chanID.TxIndex].Copy(), nil
}
// routingMsg couples a routing related routing topology update to the
// error channel.
type routingMsg struct {
@ -1521,7 +1461,7 @@ type routingMsg struct {
// ApplyChannelUpdate validates a channel update and if valid, applies it to the
// database. It returns a bool indicating whether the updates were successful.
func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate) bool {
func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool {
ch, _, _, err := b.GetChannelByID(msg.ShortChannelID)
if err != nil {
log.Errorf("Unable to retrieve channel by id: %v", err)
@ -1545,7 +1485,7 @@ func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate) bool {
return false
}
err = ValidateChannelUpdateAnn(pubKey, ch.Capacity, msg)
err = netann.ValidateChannelUpdateAnn(pubKey, ch.Capacity, msg)
if err != nil {
log.Errorf("Unable to validate channel update: %v", err)
return false

View file

@ -102,7 +102,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
// ChannelUpdates for the same channel, or NodeAnnouncements of nodes
// that are involved in this channel. This goes for both the wire
// type,s and also the types that we use within the database.
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
// We ensure that we only create a new announcement signal iff,
// one doesn't already exist, as there may be duplicate
@ -146,14 +146,14 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
// initialization needs to be done beyond just occupying a job slot.
case *models.ChannelEdgePolicy:
return
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
return
case *lnwire.NodeAnnouncement:
// TODO(roasbeef): node ann needs to wait on existing channel updates
return
case *channeldb.LightningNode:
return
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
// TODO(roasbeef): need to wait on chan ann?
return
}
@ -202,7 +202,7 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error {
jobDesc = fmt.Sprintf("job=channeldb.LightningNode, pub=%s",
vertex)
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
signals, ok = v.chanEdgeDependencies[msg.ShortChannelID]
jobDesc = fmt.Sprintf("job=lnwire.ChannelUpdate, scid=%v",
@ -216,10 +216,10 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error {
// Other types of jobs can be executed immediately, so we'll just
// return directly.
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
// TODO(roasbeef): need to wait on chan ann?
case *models.ChannelEdgeInfo:
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
}
// Release the lock once the above read is finished.
@ -275,7 +275,7 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) {
}
delete(v.chanAnnFinSignal, shortID)
}
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
finSignals, ok := v.chanAnnFinSignal[msg.ShortChannelID]
if ok {
if allow {
@ -295,13 +295,13 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) {
delete(v.nodeAnnDependencies, route.Vertex(msg.PubKeyBytes))
case *lnwire.NodeAnnouncement:
delete(v.nodeAnnDependencies, route.Vertex(msg.NodeID))
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
delete(v.chanEdgeDependencies, msg.ShortChannelID)
case *models.ChannelEdgePolicy:
shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
delete(v.chanEdgeDependencies, shortID)
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
return
}
}

View file

@ -73,9 +73,9 @@ func TestValidationBarrierQuit(t *testing.T) {
// Create a set of unique channel announcements that we will prep for
// validation.
anns := make([]*lnwire.ChannelAnnouncement, 0, numTasks)
anns := make([]*lnwire.ChannelAnnouncement1, 0, numTasks)
for i := 0; i < numTasks; i++ {
anns = append(anns, &lnwire.ChannelAnnouncement{
anns = append(anns, &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(uint64(i)),
NodeID1: nodeIDFromInt(uint64(2 * i)),
NodeID2: nodeIDFromInt(uint64(2*i + 1)),
@ -85,9 +85,9 @@ func TestValidationBarrierQuit(t *testing.T) {
// Create a set of channel updates, that must wait until their
// associated channel announcement has been verified.
chanUpds := make([]*lnwire.ChannelUpdate, 0, numTasks)
chanUpds := make([]*lnwire.ChannelUpdate1, 0, numTasks)
for i := 0; i < numTasks; i++ {
chanUpds = append(chanUpds, &lnwire.ChannelUpdate{
chanUpds = append(chanUpds, &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(uint64(i)),
})
barrier.InitJobDependencies(chanUpds[i])

View file

@ -86,7 +86,7 @@ type scidAliasHandler interface {
// HTLCs on option_scid_alias channels.
attachFailAliasUpdate(failClosure func(
sid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate)
incoming bool) *lnwire.ChannelUpdate1)
// getAliases fetches the link's underlying aliases. This is used by
// the Switch to determine whether to forward an HTLC and where to

View file

@ -120,7 +120,8 @@ type ChannelLinkConfig struct {
// specified when we receive an incoming HTLC. This will be used to
// provide payment senders our latest policy when sending encrypted
// error messages.
FetchLastChannelUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error)
FetchLastChannelUpdate func(lnwire.ShortChannelID) (
*lnwire.ChannelUpdate1, error)
// Peer is a lightning network node with which we have the channel link
// opened.
@ -262,7 +263,7 @@ type ChannelLinkConfig struct {
// FailAliasUpdate is a function used to fail an HTLC for an
// option_scid_alias channel.
FailAliasUpdate func(sid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate
incoming bool) *lnwire.ChannelUpdate1
// GetAliases is used by the link and switch to fetch the set of
// aliases for a given link.
@ -765,7 +766,7 @@ func shouldAdjustCommitFee(netFee, chanFee,
}
// failCb is used to cut down on the argument verbosity.
type failCb func(update *lnwire.ChannelUpdate) lnwire.FailureMessage
type failCb func(update *lnwire.ChannelUpdate1) lnwire.FailureMessage
// createFailureWithUpdate creates a ChannelUpdate when failing an incoming or
// outgoing HTLC. It may return a FailureMessage that references a channel's
@ -2949,7 +2950,7 @@ func (l *channelLink) getAliases() []lnwire.ShortChannelID {
//
// Part of the scidAliasHandler interface.
func (l *channelLink) attachFailAliasUpdate(closure func(
sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate) {
sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate1) {
l.Lock()
l.cfg.FailAliasUpdate = closure
@ -3041,7 +3042,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte,
// As part of the returned error, we'll send our latest routing
// policy so the sending node obtains the most up to date data.
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewFeeInsufficient(amtToForward, *upd)
}
failure := l.createFailureWithUpdate(false, originalScid, cb)
@ -3069,7 +3070,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte,
// Grab the latest routing policy so the sending node is up to
// date with our current policy.
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewIncorrectCltvExpiry(
incomingTimeout, *upd,
)
@ -3118,7 +3119,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy,
// As part of the returned error, we'll send our latest routing
// policy so the sending node obtains the most up to date data.
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewAmountBelowMinimum(amt, *upd)
}
failure := l.createFailureWithUpdate(false, originalScid, cb)
@ -3133,7 +3134,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy,
// As part of the returned error, we'll send our latest routing
// policy so the sending node obtains the most up-to-date data.
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewTemporaryChannelFailure(upd)
}
failure := l.createFailureWithUpdate(false, originalScid, cb)
@ -3148,7 +3149,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy,
"outgoing_expiry=%v, best_height=%v", payHash[:],
timeout, heightNow)
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewExpiryTooSoon(*upd)
}
failure := l.createFailureWithUpdate(false, originalScid, cb)
@ -3168,7 +3169,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy,
if amt > l.Bandwidth() {
l.log.Warnf("insufficient bandwidth to route htlc: %v is "+
"larger than %v", amt, l.Bandwidth())
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage {
return lnwire.NewTemporaryChannelFailure(upd)
}
failure := l.createFailureWithUpdate(false, originalScid, cb)
@ -3680,7 +3681,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) {
l.log.Errorf("unable to encode the "+
"remaining route %v", err)
cb := func(upd *lnwire.ChannelUpdate) lnwire.FailureMessage {
cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { //nolint:lll
return lnwire.NewTemporaryChannelFailure(upd)
}

View file

@ -6166,13 +6166,13 @@ func TestForwardingAsymmetricTimeLockPolicies(t *testing.T) {
// forwarding policy.
func TestCheckHtlcForward(t *testing.T) {
fetchLastChannelUpdate := func(lnwire.ShortChannelID) (
*lnwire.ChannelUpdate, error) {
*lnwire.ChannelUpdate1, error) {
return &lnwire.ChannelUpdate{}, nil
return &lnwire.ChannelUpdate1{}, nil
}
failAliasUpdate := func(sid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate {
incoming bool) *lnwire.ChannelUpdate1 {
return nil
}

View file

@ -167,7 +167,7 @@ type mockServer struct {
var _ lnpeer.Peer = (*mockServer)(nil)
func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) {
signAliasUpdate := func(u *lnwire.ChannelUpdate) (*ecdsa.Signature,
signAliasUpdate := func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
error) {
return testSig, nil
@ -183,9 +183,9 @@ func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error)
events: make(map[time.Time]channeldb.ForwardingEvent),
},
FetchLastChannelUpdate: func(scid lnwire.ShortChannelID) (
*lnwire.ChannelUpdate, error) {
*lnwire.ChannelUpdate1, error) {
return &lnwire.ChannelUpdate{
return &lnwire.ChannelUpdate1{
ShortChannelID: scid,
}, nil
},
@ -735,7 +735,7 @@ type mockChannelLink struct {
checkHtlcForwardResult *LinkError
failAliasUpdate func(sid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate
incoming bool) *lnwire.ChannelUpdate1
confirmedZC bool
}
@ -870,7 +870,7 @@ func (f *mockChannelLink) AttachMailBox(mailBox MailBox) {
}
func (f *mockChannelLink) attachFailAliasUpdate(closure func(
sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate) {
sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate1) {
f.failAliasUpdate = closure
}

View file

@ -173,7 +173,8 @@ type Config struct {
// specified when we receive an incoming HTLC. This will be used to
// provide payment senders our latest policy when sending encrypted
// error messages.
FetchLastChannelUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error)
FetchLastChannelUpdate func(lnwire.ShortChannelID) (
*lnwire.ChannelUpdate1, error)
// Notifier is an instance of a chain notifier that we'll use to signal
// the switch when a new block has arrived.
@ -220,7 +221,7 @@ type Config struct {
// option_scid_alias channels. This avoids a potential privacy leak by
// replacing the public, confirmed SCID with the alias in the
// ChannelUpdate.
SignAliasUpdate func(u *lnwire.ChannelUpdate) (*ecdsa.Signature,
SignAliasUpdate func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
error)
// IsAlias returns whether or not a given SCID is an alias.
@ -2640,7 +2641,7 @@ func (s *Switch) failMailboxUpdate(outgoingScid,
// and the caller is expected to handle this properly. In this case, a return
// to the original non-alias behavior is expected.
func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate {
incoming bool) *lnwire.ChannelUpdate1 {
// This function does not defer the unlocking because of the database
// lookups for ChannelUpdate.

View file

@ -3951,7 +3951,7 @@ func TestSwitchHoldForward(t *testing.T) {
// Simulate an error during the composition of the failure message.
currentCallback := c.s.cfg.FetchLastChannelUpdate
c.s.cfg.FetchLastChannelUpdate = func(
lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, error) {
return nil, errors.New("cannot fetch update")
}

View file

@ -91,8 +91,10 @@ func genIDs() (lnwire.ChannelID, lnwire.ChannelID, lnwire.ShortChannelID,
// mockGetChanUpdateMessage helper function which returns topology update of
// the channel
func mockGetChanUpdateMessage(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
return &lnwire.ChannelUpdate{
func mockGetChanUpdateMessage(_ lnwire.ShortChannelID) (*lnwire.ChannelUpdate1,
error) {
return &lnwire.ChannelUpdate1{
Signature: wireSig,
}, nil
}

View file

@ -1626,7 +1626,7 @@ func marshallWireError(msg lnwire.FailureMessage,
// marshallChannelUpdate marshalls a channel update as received over the wire to
// the router rpc format.
func marshallChannelUpdate(update *lnwire.ChannelUpdate) *lnrpc.ChannelUpdate {
func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
if update == nil {
return nil
}

View file

@ -21,6 +21,8 @@ import (
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
"github.com/lightningnetwork/lnd/lnwire"
)
const (
@ -671,3 +673,91 @@ func SupportedWallets() []string {
return supportedWallets
}
// 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,
quit chan struct{}) (*wire.MsgTx, error) {
txChan := make(chan *wire.MsgTx, 1)
errChan := make(chan error, 1)
go func() {
tx, err := FetchFundingTx(chain, chanID)
if err != nil {
errChan <- err
return
}
txChan <- tx
}()
select {
case tx := <-txChan:
return tx, nil
case err := <-errChan:
return nil, err
case <-quit:
return nil, fmt.Errorf("quit channel passed to " +
"lnwallet.FetchFundingTxWrapper has been closed")
}
}
// FetchFundingTx uses the given BlockChainIO to fetch and return the funding
// transaction identified by the passed short channel ID.
//
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
// later use getblocktxn).
func FetchFundingTx(chain BlockChainIO,
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.
blockNum := int64(chanID.BlockHeight)
blockHash, err := chain.GetBlockHash(blockNum)
if err != nil {
return nil, err
}
fundingBlock, err := chain.GetBlock(blockHash)
if err != nil {
return nil, err
}
// As a sanity check, ensure that the advertised transaction index is
// within the bounds of the total number of transactions within a
// block.
numTxns := uint32(len(fundingBlock.Transactions))
if chanID.TxIndex > numTxns-1 {
return nil, fmt.Errorf("tx_index=#%v "+
"is out of range (max_index=%v), network_chan_id=%v",
chanID.TxIndex, numTxns-1, chanID)
}
return fundingBlock.Transactions[chanID.TxIndex].Copy(), nil
}
// 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,
quit chan struct{}) ([]byte, error) {
tx, err := FetchFundingTxWrapper(chain, chanID, quit)
if err != nil {
return nil, err
}
outputLocator := chanvalidate.ShortChanIDChanLocator{
ID: *chanID,
}
output, _, err := outputLocator.Locate(tx)
if err != nil {
return nil, err
}
return output.PkScript, nil
}

View file

@ -5,11 +5,11 @@ import (
"io"
)
// AnnounceSignatures is a direct message between two endpoints of a
// AnnounceSignatures1 is a direct message between two endpoints of a
// channel and serves as an opt-in mechanism to allow the announcement of
// the channel to the rest of the network. It contains the necessary
// signatures by the sender to construct the channel announcement message.
type AnnounceSignatures struct {
type AnnounceSignatures1 struct {
// ChannelID is the unique description of the funding transaction.
// 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
@ -43,15 +43,19 @@ type AnnounceSignatures struct {
ExtraOpaqueData ExtraOpaqueData
}
// A compile time check to ensure AnnounceSignatures implements the
// A compile time check to ensure AnnounceSignatures1 implements the
// lnwire.Message interface.
var _ Message = (*AnnounceSignatures)(nil)
var _ Message = (*AnnounceSignatures1)(nil)
// Decode deserializes a serialized AnnounceSignatures stored in the passed
// A compile time check to ensure AnnounceSignatures1 implements the
// lnwire.AnnounceSignatures interface.
var _ AnnounceSignatures = (*AnnounceSignatures1)(nil)
// Decode deserializes a serialized AnnounceSignatures1 stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures) Decode(r io.Reader, pver uint32) error {
func (a *AnnounceSignatures1) Decode(r io.Reader, _ uint32) error {
return ReadElements(r,
&a.ChannelID,
&a.ShortChannelID,
@ -61,11 +65,11 @@ func (a *AnnounceSignatures) Decode(r io.Reader, pver uint32) error {
)
}
// Encode serializes the target AnnounceSignatures into the passed io.Writer
// Encode serializes the target AnnounceSignatures1 into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures) Encode(w *bytes.Buffer, pver uint32) error {
func (a *AnnounceSignatures1) Encode(w *bytes.Buffer, _ uint32) error {
if err := WriteChannelID(w, a.ChannelID); err != nil {
return err
}
@ -89,6 +93,20 @@ func (a *AnnounceSignatures) Encode(w *bytes.Buffer, pver uint32) error {
// wire.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures) MsgType() MessageType {
func (a *AnnounceSignatures1) MsgType() MessageType {
return MsgAnnounceSignatures
}
// SCID returns the ShortChannelID of the channel.
//
// This is part of the lnwire.AnnounceSignatures interface.
func (a *AnnounceSignatures1) SCID() ShortChannelID {
return a.ShortChannelID
}
// ChanID returns the ChannelID identifying the channel.
//
// This is part of the lnwire.AnnounceSignatures interface.
func (a *AnnounceSignatures1) ChanID() ChannelID {
return a.ChannelID
}

View file

@ -0,0 +1,97 @@
package lnwire
import (
"bytes"
"io"
)
// AnnounceSignatures2 is a direct message between two endpoints of a
// channel and serves as an opt-in mechanism to allow the announcement of
// a taproot channel to the rest of the network. It contains the necessary
// signatures by the sender to construct the channel_announcement_2 message.
type AnnounceSignatures2 struct {
// ChannelID is the unique description of the funding transaction.
// 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
// 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
// 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
}
// A compile time check to ensure AnnounceSignatures2 implements the
// lnwire.Message interface.
var _ Message = (*AnnounceSignatures2)(nil)
// Decode deserializes a serialized AnnounceSignatures2 stored in the passed
// io.Reader observing the specified protocol version.
//
// 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 {
return err
}
if err := WriteShortChannelID(w, a.ShortChannelID); err != nil {
return err
}
if err := WriteElement(w, a.PartialSignature); err != nil {
return err
}
return WriteBytes(w, a.ExtraOpaqueData)
}
// MsgType returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (a *AnnounceSignatures2) MsgType() MessageType {
return MsgAnnounceSignatures2
}
// SCID returns the ShortChannelID of the channel.
//
// NOTE: this is part of the AnnounceSignatures interface.
func (a *AnnounceSignatures2) SCID() ShortChannelID {
return a.ShortChannelID
}
// ChanID returns the ChannelID identifying the channel.
//
// NOTE: this is part of the AnnounceSignatures interface.
func (a *AnnounceSignatures2) ChanID() ChannelID {
return a.ChannelID
}

View file

@ -7,10 +7,10 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
// ChannelAnnouncement message is used to announce the existence of a channel
// ChannelAnnouncement1 message is used to announce the existence of a channel
// between two peers in the overlay, which is propagated by the discovery
// service over broadcast handler.
type ChannelAnnouncement struct {
type ChannelAnnouncement1 struct {
// This signatures are used by nodes in order to create cross
// references between node's channel and node. Requiring both nodes
// to sign indicates they are both willing to route other payments via
@ -60,13 +60,13 @@ type ChannelAnnouncement struct {
// A compile time check to ensure ChannelAnnouncement implements the
// lnwire.Message interface.
var _ Message = (*ChannelAnnouncement)(nil)
var _ Message = (*ChannelAnnouncement1)(nil)
// Decode deserializes a serialized ChannelAnnouncement stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (a *ChannelAnnouncement) Decode(r io.Reader, pver uint32) error {
func (a *ChannelAnnouncement1) Decode(r io.Reader, pver uint32) error {
return ReadElements(r,
&a.NodeSig1,
&a.NodeSig2,
@ -87,7 +87,7 @@ func (a *ChannelAnnouncement) Decode(r io.Reader, pver uint32) error {
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *ChannelAnnouncement) Encode(w *bytes.Buffer, pver uint32) error {
func (a *ChannelAnnouncement1) Encode(w *bytes.Buffer, pver uint32) error {
if err := WriteSig(w, a.NodeSig1); err != nil {
return err
}
@ -139,13 +139,13 @@ func (a *ChannelAnnouncement) Encode(w *bytes.Buffer, pver uint32) error {
// wire.
//
// This is part of the lnwire.Message interface.
func (a *ChannelAnnouncement) MsgType() MessageType {
func (a *ChannelAnnouncement1) MsgType() MessageType {
return MsgChannelAnnouncement
}
// DataToSign is used to retrieve part of the announcement message which should
// be signed.
func (a *ChannelAnnouncement) DataToSign() ([]byte, error) {
func (a *ChannelAnnouncement1) DataToSign() ([]byte, error) {
// We should not include the signatures itself.
b := make([]byte, 0, MaxMsgBody)
buf := bytes.NewBuffer(b)
@ -184,3 +184,38 @@ func (a *ChannelAnnouncement) DataToSign() ([]byte, error) {
return buf.Bytes(), nil
}
// Node1KeyBytes returns the bytes representing the public key of node 1 in the
// channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (a *ChannelAnnouncement1) Node1KeyBytes() [33]byte {
return a.NodeID1
}
// Node2KeyBytes returns the bytes representing the public key of node 2 in the
// channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (a *ChannelAnnouncement1) Node2KeyBytes() [33]byte {
return a.NodeID2
}
// GetChainHash returns the hash of the chain which this channel's funding
// transaction is confirmed in.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (a *ChannelAnnouncement1) GetChainHash() chainhash.Hash {
return a.ChainHash
}
// SCID returns the short channel ID of the channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (a *ChannelAnnouncement1) SCID() ShortChannelID {
return a.ShortChannelID
}
// A compile-time check to ensure that ChannelAnnouncement1 implements the
// ChannelAnnouncement interface.
var _ ChannelAnnouncement = (*ChannelAnnouncement1)(nil)

View file

@ -0,0 +1,234 @@
package lnwire
import (
"bytes"
"io"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/tlv"
)
// ChannelAnnouncement2 message is used to announce the existence of a taproot
// channel between two peers in the network.
type ChannelAnnouncement2 struct {
// Signature is a Schnorr signature over the TLV stream of the message.
Signature Sig
// ChainHash denotes the target chain that this channel was opened
// within. This value should be the genesis hash of the target chain.
ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash]
// Features is the feature vector that encodes the features supported
// by the target node. This field can be used to signal the type of the
// channel, or modifications to the fields that would normally follow
// this vector.
Features tlv.RecordT[tlv.TlvType2, RawFeatureVector]
// ShortChannelID is the unique description of the funding transaction,
// or where exactly it's located within the target blockchain.
ShortChannelID tlv.RecordT[tlv.TlvType4, ShortChannelID]
// Capacity is the number of satoshis of the capacity of this channel.
// It must be less than or equal to the value of the on-chain funding
// output.
Capacity tlv.RecordT[tlv.TlvType6, uint64]
// NodeID1 is the numerically-lesser public key ID of one of the channel
// operators.
NodeID1 tlv.RecordT[tlv.TlvType8, [33]byte]
// NodeID2 is the numerically-greater public key ID of one of the
// channel operators.
NodeID2 tlv.RecordT[tlv.TlvType10, [33]byte]
// BitcoinKey1 is the public key of the key used by Node1 in the
// construction of the on-chain funding transaction. This is an optional
// field and only needs to be set if the 4-of-4 MuSig construction was
// used in the creation of the message signature.
BitcoinKey1 tlv.OptionalRecordT[tlv.TlvType12, [33]byte]
// BitcoinKey2 is the public key of the key used by Node2 in the
// construction of the on-chain funding transaction. This is an optional
// field and only needs to be set if the 4-of-4 MuSig construction was
// used in the creation of the message signature.
BitcoinKey2 tlv.OptionalRecordT[tlv.TlvType14, [33]byte]
// MerkleRootHash is the hash used to create the optional tweak in the
// funding output. If this is not set but the bitcoin keys are, then
// the funding output is a pure 2-of-2 MuSig aggregate public key.
MerkleRootHash tlv.OptionalRecordT[tlv.TlvType16, [32]byte]
// 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
}
// Decode deserializes a serialized AnnounceSignatures1 stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error {
err := ReadElement(r, &c.Signature)
if err != nil {
return err
}
c.Signature.ForceSchnorr()
return c.DecodeTLVRecords(r)
}
// DecodeTLVRecords decodes only the TLV section of the message.
func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error {
// First extract into extra opaque data.
var tlvRecords ExtraOpaqueData
if err := ReadElements(r, &tlvRecords); err != nil {
return err
}
var (
chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]()
btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]()
merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]()
)
typeMap, err := tlvRecords.ExtractRecords(
&chainHash, &c.Features, &c.ShortChannelID, &c.Capacity,
&c.NodeID1, &c.NodeID2, &btcKey1, &btcKey2, &merkleRootHash,
)
if err != nil {
return err
}
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
c.ChainHash.Val = chainHash.Val
}
if _, ok := typeMap[c.BitcoinKey1.TlvType()]; ok {
c.BitcoinKey1 = tlv.SomeRecordT(btcKey1)
}
if _, ok := typeMap[c.BitcoinKey2.TlvType()]; ok {
c.BitcoinKey2 = tlv.SomeRecordT(btcKey2)
}
if _, ok := typeMap[c.MerkleRootHash.TlvType()]; ok {
c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash)
}
if len(tlvRecords) != 0 {
c.ExtraOpaqueData = tlvRecords
}
return nil
}
// Encode serializes the target AnnounceSignatures1 into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error {
_, err := w.Write(c.Signature.RawBytes())
if err != nil {
return err
}
_, err = c.DataToSign()
if err != nil {
return err
}
return WriteBytes(w, c.ExtraOpaqueData)
}
// DataToSign encodes the data to be signed into the ExtraOpaqueData member and
// returns it.
func (c *ChannelAnnouncement2) DataToSign() ([]byte, error) {
// The chain-hash record is only included if it is _not_ equal to the
// bitcoin mainnet genisis block hash.
var recordProducers []tlv.RecordProducer
if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) {
hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
hash.Val = c.ChainHash.Val
recordProducers = append(recordProducers, &hash)
}
recordProducers = append(recordProducers,
&c.Features, &c.ShortChannelID, &c.Capacity, &c.NodeID1,
&c.NodeID2,
)
c.BitcoinKey1.WhenSome(func(key tlv.RecordT[tlv.TlvType12, [33]byte]) {
recordProducers = append(recordProducers, &key)
})
c.BitcoinKey2.WhenSome(func(key tlv.RecordT[tlv.TlvType14, [33]byte]) {
recordProducers = append(recordProducers, &key)
})
c.MerkleRootHash.WhenSome(
func(hash tlv.RecordT[tlv.TlvType16, [32]byte]) {
recordProducers = append(recordProducers, &hash)
},
)
err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...)
if err != nil {
return nil, err
}
return c.ExtraOpaqueData, nil
}
// MsgType returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) MsgType() MessageType {
return MsgChannelAnnouncement2
}
// A compile time check to ensure ChannelAnnouncement2 implements the
// lnwire.Message interface.
var _ Message = (*ChannelAnnouncement2)(nil)
// Node1KeyBytes returns the bytes representing the public key of node 1 in the
// channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (c *ChannelAnnouncement2) Node1KeyBytes() [33]byte {
return c.NodeID1.Val
}
// Node2KeyBytes returns the bytes representing the public key of node 2 in the
// channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (c *ChannelAnnouncement2) Node2KeyBytes() [33]byte {
return c.NodeID2.Val
}
// GetChainHash returns the hash of the chain which this channel's funding
// transaction is confirmed in.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (c *ChannelAnnouncement2) GetChainHash() chainhash.Hash {
return c.ChainHash.Val
}
// SCID returns the short channel ID of the channel.
//
// NOTE: This is part of the ChannelAnnouncement interface.
func (c *ChannelAnnouncement2) SCID() ShortChannelID {
return c.ShortChannelID.Val
}
// A compile-time check to ensure that ChannelAnnouncement2 implements the
// ChannelAnnouncement interface.
var _ ChannelAnnouncement = (*ChannelAnnouncement2)(nil)

View file

@ -33,6 +33,16 @@ type ChannelReady struct {
// to accept a new commitment state transition.
NextLocalNonce OptMusig2NonceTLV
// AnnouncementNodeNonce is an optional field that stores a public
// nonce that will be used along with the node's ID key during signing
// of the ChannelAnnouncement2 message.
AnnouncementNodeNonce tlv.OptionalRecordT[tlv.TlvType0, Musig2Nonce]
// AnnouncementBitcoinNonce is an optional field that stores a public
// nonce that will be used along with the node's bitcoin key during
// signing of the ChannelAnnouncement2 message.
AnnouncementBitcoinNonce tlv.OptionalRecordT[tlv.TlvType2, Musig2Nonce]
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
// be used to specify optional data such as custom TLV fields.
@ -78,9 +88,11 @@ func (c *ChannelReady) Decode(r io.Reader, _ uint32) error {
var (
aliasScid ShortChannelID
localNonce = c.NextLocalNonce.Zero()
nodeNonce = tlv.ZeroRecordT[tlv.TlvType0, Musig2Nonce]()
btcNonce = tlv.ZeroRecordT[tlv.TlvType2, Musig2Nonce]()
)
typeMap, err := tlvRecords.ExtractRecords(
&aliasScid, &localNonce,
&btcNonce, &aliasScid, &nodeNonce, &localNonce,
)
if err != nil {
return err
@ -94,6 +106,14 @@ func (c *ChannelReady) Decode(r io.Reader, _ uint32) error {
if val, ok := typeMap[c.NextLocalNonce.TlvType()]; ok && val == nil {
c.NextLocalNonce = tlv.SomeRecordT(localNonce)
}
val, ok := typeMap[c.AnnouncementBitcoinNonce.TlvType()]
if ok && val == nil {
c.AnnouncementBitcoinNonce = tlv.SomeRecordT(btcNonce)
}
val, ok = typeMap[c.AnnouncementNodeNonce.TlvType()]
if ok && val == nil {
c.AnnouncementNodeNonce = tlv.SomeRecordT(nodeNonce)
}
if len(tlvRecords) != 0 {
c.ExtraData = tlvRecords
@ -117,13 +137,24 @@ func (c *ChannelReady) Encode(w *bytes.Buffer, _ uint32) error {
}
// We'll only encode the AliasScid in a TLV segment if it exists.
recordProducers := make([]tlv.RecordProducer, 0, 2)
recordProducers := make([]tlv.RecordProducer, 0, 4)
if c.AliasScid != nil {
recordProducers = append(recordProducers, c.AliasScid)
}
c.NextLocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
c.AnnouncementBitcoinNonce.WhenSome(
func(nonce tlv.RecordT[tlv.TlvType2, Musig2Nonce]) {
recordProducers = append(recordProducers, &nonce)
},
)
c.AnnouncementNodeNonce.WhenSome(
func(nonce tlv.RecordT[tlv.TlvType0, Musig2Nonce]) {
recordProducers = append(recordProducers, &nonce)
},
)
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
if err != nil {
return err

View file

@ -56,11 +56,11 @@ func (c ChanUpdateChanFlags) String() string {
return fmt.Sprintf("%08b", c)
}
// ChannelUpdate message is used after channel has been initially announced.
// ChannelUpdate1 message is used after channel has been initially announced.
// Each side independently announces its fees and minimum expiry for HTLCs and
// other parameters. Also this message is used to redeclare initially set
// channel parameters.
type ChannelUpdate struct {
type ChannelUpdate1 struct {
// Signature is used to validate the announced data and prove the
// ownership of node id.
Signature Sig
@ -122,13 +122,13 @@ type ChannelUpdate struct {
// A compile time check to ensure ChannelUpdate implements the lnwire.Message
// interface.
var _ Message = (*ChannelUpdate)(nil)
var _ Message = (*ChannelUpdate1)(nil)
// Decode deserializes a serialized ChannelUpdate stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (a *ChannelUpdate) Decode(r io.Reader, pver uint32) error {
func (a *ChannelUpdate1) Decode(r io.Reader, pver uint32) error {
err := ReadElements(r,
&a.Signature,
a.ChainHash[:],
@ -159,7 +159,7 @@ func (a *ChannelUpdate) Decode(r io.Reader, pver uint32) error {
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *ChannelUpdate) Encode(w *bytes.Buffer, pver uint32) error {
func (a *ChannelUpdate1) Encode(w *bytes.Buffer, pver uint32) error {
if err := WriteSig(w, a.Signature); err != nil {
return err
}
@ -217,13 +217,13 @@ func (a *ChannelUpdate) Encode(w *bytes.Buffer, pver uint32) error {
// wire.
//
// This is part of the lnwire.Message interface.
func (a *ChannelUpdate) MsgType() MessageType {
func (a *ChannelUpdate1) MsgType() MessageType {
return MsgChannelUpdate
}
// DataToSign is used to retrieve part of the announcement message which should
// be signed.
func (a *ChannelUpdate) DataToSign() ([]byte, error) {
func (a *ChannelUpdate1) DataToSign() ([]byte, error) {
// We should not include the signatures itself.
b := make([]byte, 0, MaxMsgBody)
buf := bytes.NewBuffer(b)
@ -279,3 +279,91 @@ func (a *ChannelUpdate) DataToSign() ([]byte, error) {
return buf.Bytes(), nil
}
// SCID returns the ShortChannelID of the channel that the update applies to.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) SCID() ShortChannelID {
return a.ShortChannelID
}
// IsNode1 is true if the update was produced by node 1 of the channel peers.
// Node 1 is the node with the lexicographically smaller public key.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) IsNode1() bool {
return a.ChannelFlags&ChanUpdateDirection == 0
}
// IsDisabled is true if the update is announcing that the channel should be
// considered disabled.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) IsDisabled() bool {
return a.ChannelFlags&ChanUpdateDisabled == ChanUpdateDisabled
}
// GetChainHash returns the hash of the chain that the message is referring to.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) GetChainHash() chainhash.Hash {
return a.ChainHash
}
// ForwardingPolicy returns the set of forwarding constraints of the update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) ForwardingPolicy() *ForwardingPolicy {
return &ForwardingPolicy{
TimeLockDelta: a.TimeLockDelta,
BaseFee: MilliSatoshi(a.BaseFee),
FeeRate: MilliSatoshi(a.FeeRate),
MinHTLC: a.HtlcMinimumMsat,
HasMaxHTLC: a.MessageFlags.HasMaxHtlc(),
MaxHTLC: a.HtlcMaximumMsat,
}
}
// CmpAge can be used to determine if the update is older or newer than the
// passed update. It returns 1 if this update is newer, -1 if it is older, and
// 0 if they are the same age.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) CmpAge(update ChannelUpdate) (CompareResult, error) {
other, ok := update.(*ChannelUpdate1)
if !ok {
return 0, fmt.Errorf("expected *ChannelUpdate1, got: %T",
update)
}
switch {
case a.Timestamp > other.Timestamp:
return GreaterThan, nil
case a.Timestamp < other.Timestamp:
return LessThan, nil
default:
return EqualTo, nil
}
}
// SetDisabledFlag can be used to adjust the disabled flag of an update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) SetDisabledFlag(disabled bool) {
if disabled {
a.ChannelFlags |= ChanUpdateDisabled
} else {
a.ChannelFlags &= ^ChanUpdateDisabled
}
}
// SetSCID can be used to overwrite the SCID of the update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (a *ChannelUpdate1) SetSCID(scid ShortChannelID) {
a.ShortChannelID = scid
}
// A compile time assertion to ensure ChannelUpdate1 implements the
// ChannelUpdate interface.
var _ ChannelUpdate = (*ChannelUpdate1)(nil)

441
lnwire/channel_update_2.go Normal file
View file

@ -0,0 +1,441 @@
package lnwire
import (
"bytes"
"fmt"
"io"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/tlv"
)
const (
defaultCltvExpiryDelta = uint16(80)
defaultHtlcMinMsat = MilliSatoshi(1)
defaultFeeBaseMsat = uint32(1000)
defaultFeeProportionalMillionths = uint32(1)
)
// ChannelUpdate2 message is used after taproot channel has been initially
// announced. Each side independently announces its fees and minimum expiry for
// HTLCs and other parameters. This message is also used to redeclare initially
// set channel parameters.
type ChannelUpdate2 struct {
// Signature is used to validate the announced data and prove the
// ownership of node id.
Signature Sig
// ChainHash denotes the target chain that this channel was opened
// within. This value should be the genesis hash of the target chain.
// Along with the short channel ID, this uniquely identifies the
// channel globally in a blockchain.
ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash]
// ShortChannelID is the unique description of the funding transaction.
ShortChannelID tlv.RecordT[tlv.TlvType2, ShortChannelID]
// BlockHeight allows ordering in the case of multiple announcements. We
// should ignore the message if block height is not greater than the
// last-received. The block height must always be greater or equal to
// the block height that the channel funding transaction was confirmed
// in.
BlockHeight tlv.RecordT[tlv.TlvType4, uint32]
// DisabledFlags is an optional bitfield that describes various reasons
// that the node is communicating that the channel should be considered
// disabled.
DisabledFlags tlv.RecordT[tlv.TlvType6, ChanUpdateDisableFlags]
// SecondPeer is used to indicate which node the channel node has
// created and signed this message. If this field is present, it was
// node 2 otherwise it was node 1.
SecondPeer tlv.OptionalRecordT[tlv.TlvType8, TrueBoolean]
// CLTVExpiryDelta is the minimum number of blocks this node requires to
// be added to the expiry of HTLCs. This is a security parameter
// determined by the node operator. This value represents the required
// gap between the time locks of the incoming and outgoing HTLC's set
// to this node.
CLTVExpiryDelta tlv.RecordT[tlv.TlvType10, uint16]
// HTLCMinimumMsat is the minimum HTLC value which will be accepted.
HTLCMinimumMsat tlv.RecordT[tlv.TlvType12, MilliSatoshi]
// HtlcMaximumMsat is the maximum HTLC value which will be accepted.
HTLCMaximumMsat tlv.RecordT[tlv.TlvType14, MilliSatoshi]
// FeeBaseMsat is the base fee that must be used for incoming HTLC's to
// this particular channel. This value will be tacked onto the required
// for a payment independent of the size of the payment.
FeeBaseMsat tlv.RecordT[tlv.TlvType16, uint32]
// FeeProportionalMillionths is the fee rate that will be charged per
// millionth of a satoshi.
FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32]
// ExtraOpaqueData is the set of data that was appended to this message
// to fill out the full maximum transport message size. These fields can
// be used to specify optional data such as custom TLV fields.
ExtraOpaqueData ExtraOpaqueData
}
// Decode deserializes a serialized ChannelUpdate2 stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error {
err := ReadElement(r, &c.Signature)
if err != nil {
return err
}
c.Signature.ForceSchnorr()
return c.DecodeTLVRecords(r)
}
// DecodeTLVRecords decodes only the TLV section of the message.
func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error {
// First extract into extra opaque data.
var tlvRecords ExtraOpaqueData
if err := ReadElements(r, &tlvRecords); err != nil {
return err
}
var (
chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
secondPeer = tlv.ZeroRecordT[tlv.TlvType8, TrueBoolean]()
)
typeMap, err := tlvRecords.ExtractRecords(
&chainHash, &c.ShortChannelID, &c.BlockHeight, &c.DisabledFlags,
&secondPeer, &c.CLTVExpiryDelta, &c.HTLCMinimumMsat,
&c.HTLCMaximumMsat, &c.FeeBaseMsat,
&c.FeeProportionalMillionths,
)
if err != nil {
return err
}
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
c.ChainHash.Val = chainHash.Val
}
// The presence of the second_peer tlv type indicates "true".
if _, ok := typeMap[c.SecondPeer.TlvType()]; ok {
c.SecondPeer = tlv.SomeRecordT(secondPeer)
}
// If the CLTV expiry delta was not encoded, then set it to the default
// value.
if _, ok := typeMap[c.CLTVExpiryDelta.TlvType()]; !ok {
c.CLTVExpiryDelta.Val = defaultCltvExpiryDelta
}
// If the HTLC Minimum msat was not encoded, then set it to the default
// value.
if _, ok := typeMap[c.HTLCMinimumMsat.TlvType()]; !ok {
c.HTLCMinimumMsat.Val = defaultHtlcMinMsat
}
// If the base fee was not encoded, then set it to the default value.
if _, ok := typeMap[c.FeeBaseMsat.TlvType()]; !ok {
c.FeeBaseMsat.Val = defaultFeeBaseMsat
}
// If the proportional fee was not encoded, then set it to the default
// value.
if _, ok := typeMap[c.FeeProportionalMillionths.TlvType()]; !ok {
c.FeeProportionalMillionths.Val = defaultFeeProportionalMillionths //nolint:lll
}
if len(tlvRecords) != 0 {
c.ExtraOpaqueData = tlvRecords
}
return nil
}
// Encode serializes the target ChannelUpdate2 into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error {
_, err := w.Write(c.Signature.RawBytes())
if err != nil {
return err
}
_, err = c.DataToSign()
if err != nil {
return err
}
return WriteBytes(w, c.ExtraOpaqueData)
}
// DataToSign is used to retrieve part of the announcement message which should
// be signed. For the ChannelUpdate2 message, this includes the serialised TLV
// records.
func (c *ChannelUpdate2) DataToSign() ([]byte, error) {
// The chain-hash record is only included if it is _not_ equal to the
// bitcoin mainnet genisis block hash.
var recordProducers []tlv.RecordProducer
if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) {
hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
hash.Val = c.ChainHash.Val
recordProducers = append(recordProducers, &hash)
}
recordProducers = append(recordProducers,
&c.ShortChannelID, &c.BlockHeight,
)
// Only include the disable flags if any bit is set.
if !c.DisabledFlags.Val.IsEnabled() {
recordProducers = append(recordProducers, &c.DisabledFlags)
}
// We only need to encode the second peer boolean if it is true
c.SecondPeer.WhenSome(func(r tlv.RecordT[tlv.TlvType8, TrueBoolean]) {
recordProducers = append(recordProducers, &r)
})
// We only encode the cltv expiry delta if it is not equal to the
// default.
if c.CLTVExpiryDelta.Val != defaultCltvExpiryDelta {
recordProducers = append(recordProducers, &c.CLTVExpiryDelta)
}
if c.HTLCMinimumMsat.Val != defaultHtlcMinMsat {
recordProducers = append(recordProducers, &c.HTLCMinimumMsat)
}
recordProducers = append(recordProducers, &c.HTLCMaximumMsat)
if c.FeeBaseMsat.Val != defaultFeeBaseMsat {
recordProducers = append(recordProducers, &c.FeeBaseMsat)
}
if c.FeeProportionalMillionths.Val != defaultFeeProportionalMillionths {
recordProducers = append(
recordProducers, &c.FeeProportionalMillionths,
)
}
err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...)
if err != nil {
return nil, err
}
return c.ExtraOpaqueData, nil
}
// MsgType returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *ChannelUpdate2) MsgType() MessageType {
return MsgChannelUpdate2
}
func (c *ChannelUpdate2) ExtraData() ExtraOpaqueData {
return c.ExtraOpaqueData
}
// A compile time check to ensure ChannelUpdate2 implements the
// lnwire.Message interface.
var _ Message = (*ChannelUpdate2)(nil)
// SCID returns the ShortChannelID of the channel that the update applies to.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) SCID() ShortChannelID {
return c.ShortChannelID.Val
}
// IsNode1 is true if the update was produced by node 1 of the channel peers.
// Node 1 is the node with the lexicographically smaller public key.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) IsNode1() bool {
return c.SecondPeer.IsNone()
}
// IsDisabled is true if the update is announcing that the channel should be
// considered disabled.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) IsDisabled() bool {
return !c.DisabledFlags.Val.IsEnabled()
}
// GetChainHash returns the hash of the chain that the message is referring to.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) GetChainHash() chainhash.Hash {
return c.ChainHash.Val
}
// ForwardingPolicy returns the set of forwarding constraints of the update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) ForwardingPolicy() *ForwardingPolicy {
return &ForwardingPolicy{
TimeLockDelta: c.CLTVExpiryDelta.Val,
BaseFee: MilliSatoshi(c.FeeBaseMsat.Val),
FeeRate: MilliSatoshi(c.FeeProportionalMillionths.Val),
MinHTLC: c.HTLCMinimumMsat.Val,
HasMaxHTLC: true,
MaxHTLC: c.HTLCMaximumMsat.Val,
}
}
// CmpAge can be used to determine if the update is older or newer than the
// passed update. It returns 1 if this update is newer, -1 if it is older, and
// 0 if they are the same age.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) CmpAge(update ChannelUpdate) (CompareResult, error) {
other, ok := update.(*ChannelUpdate2)
if !ok {
return 0, fmt.Errorf("expected *ChannelUpdate2, got: %T",
update)
}
switch {
case c.BlockHeight.Val > other.BlockHeight.Val:
return GreaterThan, nil
case c.BlockHeight.Val < other.BlockHeight.Val:
return LessThan, nil
default:
return EqualTo, nil
}
}
// SetDisabledFlag can be used to adjust the disabled flag of an update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) SetDisabledFlag(disabled bool) {
if disabled {
c.DisabledFlags.Val |= ChanUpdateDisableIncoming
c.DisabledFlags.Val |= ChanUpdateDisableOutgoing
} else {
c.DisabledFlags.Val &^= ChanUpdateDisableIncoming
c.DisabledFlags.Val &^= ChanUpdateDisableOutgoing
}
}
// SetSCID can be used to overwrite the SCID of the update.
//
// NOTE: this is part of the ChannelUpdate interface.
func (c *ChannelUpdate2) SetSCID(scid ShortChannelID) {
c.ShortChannelID.Val = scid
}
// A compile time check to ensure ChannelUpdate2 implements the
// lnwire.ChannelUpdate interface.
var _ ChannelUpdate = (*ChannelUpdate2)(nil)
// ChanUpdateDisableFlags is a bit vector that can be used to indicate various
// reasons for the channel being marked as disabled.
type ChanUpdateDisableFlags uint8
const (
// ChanUpdateDisableIncoming is a bit indicates that a channel is
// disabled in the inbound direction meaning that the node broadcasting
// the update is communicating that they cannot receive funds.
ChanUpdateDisableIncoming ChanUpdateDisableFlags = 1 << iota
// ChanUpdateDisableOutgoing is a bit indicates that a channel is
// disabled in the outbound direction meaning that the node broadcasting
// the update is communicating that they cannot send or route funds.
ChanUpdateDisableOutgoing = 2
)
// IncomingDisabled returns true if the ChanUpdateDisableIncoming bit is set.
func (c ChanUpdateDisableFlags) IncomingDisabled() bool {
return c&ChanUpdateDisableIncoming == ChanUpdateDisableIncoming
}
// OutgoingDisabled returns true if the ChanUpdateDisableOutgoing bit is set.
func (c ChanUpdateDisableFlags) OutgoingDisabled() bool {
return c&ChanUpdateDisableOutgoing == ChanUpdateDisableOutgoing
}
// IsEnabled returns true if none of the disable bits are set.
func (c ChanUpdateDisableFlags) IsEnabled() bool {
return c == 0
}
// String returns the bitfield flags as a string.
func (c ChanUpdateDisableFlags) String() string {
return fmt.Sprintf("%08b", c)
}
// Record returns the tlv record for the disable flags.
func (c *ChanUpdateDisableFlags) Record() tlv.Record {
return tlv.MakeStaticRecord(0, c, 1, encodeDisableFlags,
decodeDisableFlags)
}
func encodeDisableFlags(w io.Writer, val interface{}, buf *[8]byte) error {
if v, ok := val.(*ChanUpdateDisableFlags); ok {
flagsInt := uint8(*v)
return tlv.EUint8(w, &flagsInt, buf)
}
return tlv.NewTypeForEncodingErr(val, "lnwire.ChanUpdateDisableFlags")
}
func decodeDisableFlags(r io.Reader, val interface{}, buf *[8]byte,
l uint64) error {
if v, ok := val.(*ChanUpdateDisableFlags); ok {
var flagsInt uint8
err := tlv.DUint8(r, &flagsInt, buf, l)
if err != nil {
return err
}
*v = ChanUpdateDisableFlags(flagsInt)
return nil
}
return tlv.NewTypeForDecodingErr(val, "lnwire.ChanUpdateDisableFlags",
l, l)
}
// TrueBoolean is a record that indicates true or false using the presence of
// the record. If the record is absent, it indicates false. If it is presence,
// it indicates true.
type TrueBoolean struct{}
// Record returns the tlv record for the boolean entry.
func (b *TrueBoolean) Record() tlv.Record {
return tlv.MakeStaticRecord(
0, b, 0, booleanEncoder, booleanDecoder,
)
}
func booleanEncoder(_ io.Writer, val interface{}, _ *[8]byte) error {
if _, ok := val.(*TrueBoolean); ok {
return nil
}
return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
}
func booleanDecoder(_ io.Reader, val interface{}, _ *[8]byte,
l uint64) error {
if _, ok := val.(*TrueBoolean); ok && (l == 0 || l == 1) {
return nil
}
return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
}

View file

@ -642,31 +642,39 @@ func (fv *RawFeatureVector) sizeFunc() uint64 {
// Record returns a TLV record that can be used to encode/decode raw feature
// vectors. Note that the length of the feature vector is not included, because
// it is covered by the TLV record's length field.
func (fv *RawFeatureVector) Record(recordType tlv.Type) tlv.Record {
func (fv *RawFeatureVector) Record() tlv.Record {
return tlv.MakeDynamicRecord(
recordType, fv, fv.sizeFunc, rawFeatureEncoder,
rawFeatureDecoder,
0, fv, fv.sizeFunc, rawFeatureEncoder, rawFeatureDecoder,
)
}
// rawFeatureEncoder is a custom TLV encoder for raw feature vectors.
func rawFeatureEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
if f, ok := val.(*RawFeatureVector); ok {
return f.encode(w, f.SerializeSize(), 8)
if v, ok := val.(*RawFeatureVector); ok {
// Encode the feature bits as a byte slice without its length
// prepended, as that's already taken care of by the TLV record.
fv := *v
return fv.encode(w, fv.SerializeSize(), 8)
}
return tlv.NewTypeForEncodingErr(val, "*lnwire.RawFeatureVector")
return tlv.NewTypeForEncodingErr(val, "lnwire.RawFeatureVector")
}
// rawFeatureDecoder is a custom TLV decoder for raw feature vectors.
func rawFeatureDecoder(r io.Reader, val interface{}, _ *[8]byte,
l uint64) error {
if f, ok := val.(*RawFeatureVector); ok {
return f.decode(r, int(l), 8)
if v, ok := val.(*RawFeatureVector); ok {
fv := NewRawFeatureVector()
if err := fv.decode(r, int(l), 8); err != nil {
return err
}
*v = *fv
return nil
}
return tlv.NewTypeForEncodingErr(val, "*lnwire.RawFeatureVector")
return tlv.NewTypeForEncodingErr(val, "lnwire.RawFeatureVector")
}
// FeatureVector represents a set of enabled features. The set stores

View file

@ -5,6 +5,7 @@ import (
"io"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/tlv"
)
// GossipTimestampRange is a message that allows the sender to restrict the set
@ -17,15 +18,31 @@ type GossipTimestampRange struct {
ChainHash chainhash.Hash
// FirstTimestamp is the timestamp of the earliest announcement message
// that should be sent by the receiver.
// that should be sent by the receiver. This is only to be used for
// querying message of gossip 1.0 which are timestamped using Unix
// timestamps. FirstBlockHeight and BlockRange should be used to
// query for announcement messages timestamped using block heights.
FirstTimestamp uint32
// TimestampRange is the horizon beyond the FirstTimestamp that any
// announcement messages should be sent for. The receiving node MUST
// NOT send any announcements that have a timestamp greater than
// FirstTimestamp + TimestampRange.
// FirstTimestamp + TimestampRange. This is used together with
// FirstTimestamp to query for gossip 1.0 messages timestamped with
// Unix timestamps.
TimestampRange uint32
// FirstBlockHeight is the height of earliest announcement message that
// should be sent by the receiver. This is used only for querying
// announcement messages that use block heights as a timestamp.
FirstBlockHeight tlv.OptionalRecordT[tlv.TlvType2, uint32]
// BlockRange is the horizon beyond FirstBlockHeight that any
// announcement messages should be sent for. The receiving node MUST NOT
// send any announcements that have a timestamp greater than
// FirstBlockHeight + BlockRange.
BlockRange tlv.OptionalRecordT[tlv.TlvType4, uint32]
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
// be used to specify optional data such as custom TLV fields.
@ -45,13 +62,42 @@ var _ Message = (*GossipTimestampRange)(nil)
// passed io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (g *GossipTimestampRange) Decode(r io.Reader, pver uint32) error {
return ReadElements(r,
func (g *GossipTimestampRange) Decode(r io.Reader, _ uint32) error {
err := ReadElements(r,
g.ChainHash[:],
&g.FirstTimestamp,
&g.TimestampRange,
&g.ExtraData,
)
if err != nil {
return err
}
var tlvRecords ExtraOpaqueData
if err := ReadElements(r, &tlvRecords); err != nil {
return err
}
var (
firstBlock = tlv.ZeroRecordT[tlv.TlvType2, uint32]()
blockRange = tlv.ZeroRecordT[tlv.TlvType4, uint32]()
)
typeMap, err := tlvRecords.ExtractRecords(&firstBlock, &blockRange)
if err != nil {
return err
}
if val, ok := typeMap[g.FirstBlockHeight.TlvType()]; ok && val == nil {
g.FirstBlockHeight = tlv.SomeRecordT(firstBlock)
}
if val, ok := typeMap[g.BlockRange.TlvType()]; ok && val == nil {
g.BlockRange = tlv.SomeRecordT(blockRange)
}
if len(tlvRecords) != 0 {
g.ExtraData = tlvRecords
}
return nil
}
// Encode serializes the target GossipTimestampRange into the passed io.Writer
@ -71,6 +117,22 @@ func (g *GossipTimestampRange) Encode(w *bytes.Buffer, pver uint32) error {
return err
}
recordProducers := make([]tlv.RecordProducer, 0, 2)
g.FirstBlockHeight.WhenSome(
func(height tlv.RecordT[tlv.TlvType2, uint32]) {
recordProducers = append(recordProducers, &height)
},
)
g.BlockRange.WhenSome(
func(blockRange tlv.RecordT[tlv.TlvType4, uint32]) {
recordProducers = append(recordProducers, &blockRange)
},
)
err := EncodeMessageExtraData(&g.ExtraData, recordProducers...)
if err != nil {
return err
}
return WriteBytes(w, g.ExtraData)
}

121
lnwire/interfaces.go Normal file
View file

@ -0,0 +1,121 @@
package lnwire
import "github.com/btcsuite/btcd/chaincfg/chainhash"
// AnnounceSignatures is an interface that represents a message used to
// exchange signatures of a ChannelAnnouncment message during the funding flow.
type AnnounceSignatures interface {
// SCID returns the ShortChannelID of the channel.
SCID() ShortChannelID
// ChanID returns the ChannelID identifying the channel.
ChanID() ChannelID
Message
}
// ChannelAnnouncement is an interface that must be satisfied by any message
// used to announce and prove the existence of a channel.
type ChannelAnnouncement interface {
// SCID returns the short channel ID of the channel.
SCID() ShortChannelID
// GetChainHash returns the hash of the chain which this channel's
// funding transaction is confirmed in.
GetChainHash() chainhash.Hash
// Node1KeyBytes returns the bytes representing the public key of node
// 1 in the channel.
Node1KeyBytes() [33]byte
// Node2KeyBytes returns the bytes representing the public key of node
// 2 in the channel.
Node2KeyBytes() [33]byte
Message
}
// CompareResult represents the result after comparing two things.
type CompareResult uint8
const (
// LessThan indicates that base object is less than the object it was
// compared to.
LessThan CompareResult = iota
// EqualTo indicates that the base object is equal to the object it was
// compared to.
EqualTo
// GreaterThan indicates that base object is greater than the object it
// was compared to.
GreaterThan
)
// ChannelUpdate is an interface that describes a message used to update the
// forwarding rules of a channel.
type ChannelUpdate interface {
// SCID returns the ShortChannelID of the channel that the update
// applies to.
SCID() ShortChannelID
// IsNode1 is true if the update was produced by node 1 of the channel
// peers. Node 1 is the node with the lexicographically smaller public
// key.
IsNode1() bool
// IsDisabled is true if the update is announcing that the channel
// should be considered disabled.
IsDisabled() bool
// GetChainHash returns the hash of the chain that the message is
// referring to.
GetChainHash() chainhash.Hash
// ForwardingPolicy returns the set of forwarding constraints of the
// update.
ForwardingPolicy() *ForwardingPolicy
// CmpAge can be used to determine if the update is older or newer than
// the passed update. It returns LessThan if this update is older than
// the passed update, GreaterThan if it is newer and EqualTo if they are
// the same age.
CmpAge(update ChannelUpdate) (CompareResult, error)
// SetDisabledFlag can be used to adjust the disabled flag of an update.
SetDisabledFlag(bool)
// SetSCID can be used to overwrite the SCID of the update.
SetSCID(scid ShortChannelID)
Message
}
// ForwardingPolicy defines the set of forwarding constraints advertised in a
// ChannelUpdate message.
type ForwardingPolicy struct {
// TimeLockDelta is the minimum number of blocks that the node requires
// to be added to the expiry of HTLCs. This is a security parameter
// determined by the node operator. This value represents the required
// gap between the time locks of the incoming and outgoing HTLC's set
// to this node.
TimeLockDelta uint16
// BaseFee is the base fee that must be used for incoming HTLC's to
// this particular channel. This value will be tacked onto the required
// for a payment independent of the size of the payment.
BaseFee MilliSatoshi
// FeeRate is the fee rate that will be charged per millionth of a
// satoshi.
FeeRate MilliSatoshi
// HtlcMinimumMsat is the minimum HTLC value which will be accepted.
MinHTLC MilliSatoshi
// HasMaxHTLC is true if the MaxHTLC field is provided in the update.
HasMaxHTLC bool
// HtlcMaximumMsat is the maximum HTLC value which will be accepted.
MaxHTLC MilliSatoshi
}

View file

@ -187,6 +187,11 @@ func WriteElement(w *bytes.Buffer, element interface{}) error {
return err
}
case PartialSig:
if err := e.Encode(w); err != nil {
return err
}
case PingPayload:
var l [2]byte
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
@ -936,6 +941,13 @@ func ReadElement(r io.Reader, element interface{}) error {
}
*e = addrBytes[:length]
case *PartialSig:
var sig PartialSig
if err = sig.Decode(r); err != nil {
return err
}
*e = sig
case *ExtraOpaqueData:
return e.Decode(r)

View file

@ -19,6 +19,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/lightningnetwork/lnd/fn"
@ -30,17 +31,25 @@ import (
)
var (
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb" +
"92427ae41e4649b934ca495991b7852b855")
shaHash1, _ = chainhash.NewHash(shaHash1Bytes)
outpoint1 = wire.NewOutPoint(shaHash1, 0)
testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7")
testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae")
testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571" +
"319d18e949ddfa2965fb6caa1bf0314f882d7")
testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a" +
"88121167221b6700d72a0ead154c03be696a292d24ae")
testRScalar = new(btcec.ModNScalar)
testSScalar = new(btcec.ModNScalar)
_ = testRScalar.SetByteSlice(testRBytes)
_ = testSScalar.SetByteSlice(testSBytes)
testSig = ecdsa.NewSignature(testRScalar, testSScalar)
testSchnorrSigStr, _ = hex.DecodeString("04E7F9037658A92AFEB4F2" +
"5BAE5339E3DDCA81A353493827D26F16D92308E49E2A25E9220867" +
"8A2DF86970DA91B03A8AF8815A8A60498B358DAF560B347AA557")
testSchnorrSig, _ = NewSigFromSchnorrRawSignature(testSchnorrSigStr)
)
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -156,17 +165,15 @@ func generateRandomBytes(n int) ([]byte, error) {
return b, nil
}
func randRawKey() ([33]byte, error) {
func randRawKey(t *testing.T) [33]byte {
var n [33]byte
priv, err := btcec.NewPrivateKey()
if err != nil {
return n, err
}
require.NoError(t, err)
copy(n[:], priv.PubKey().SerializeCompressed())
return n, nil
return n
}
func randDeliveryAddress(r *rand.Rand) (DeliveryAddress, error) {
@ -730,18 +737,13 @@ func TestLightningWireProtocol(t *testing.T) {
},
MsgChannelReady: func(v []reflect.Value, r *rand.Rand) {
var c [32]byte
if _, err := r.Read(c[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
_, err := r.Read(c[:])
require.NoError(t, err)
pubKey, err := randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
require.NoError(t, err)
req := NewChannelReady(ChannelID(c), pubKey)
req := NewChannelReady(c, pubKey)
if r.Int31()%2 == 0 {
scid := NewShortChanIDFromInt(uint64(r.Int63()))
@ -751,6 +753,24 @@ func TestLightningWireProtocol(t *testing.T) {
req.NextLocalNonce = someLocalNonce[NonceRecordTypeT](r)
}
if r.Int31()%2 == 0 {
nodeNonce := tlv.ZeroRecordT[
tlv.TlvType0, Musig2Nonce,
]()
nodeNonce.Val = randLocalNonce(r)
req.AnnouncementNodeNonce = tlv.SomeRecordT(
nodeNonce,
)
btcNonce := tlv.ZeroRecordT[
tlv.TlvType2, Musig2Nonce,
]()
btcNonce.Val = randLocalNonce(r)
req.AnnouncementBitcoinNonce = tlv.SomeRecordT(
btcNonce,
)
}
v[0] = reflect.ValueOf(*req)
},
MsgShutdown: func(v []reflect.Value, r *rand.Rand) {
@ -979,8 +999,14 @@ func TestLightningWireProtocol(t *testing.T) {
},
MsgChannelAnnouncement: func(v []reflect.Value, r *rand.Rand) {
var err error
req := ChannelAnnouncement{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
req := ChannelAnnouncement1{
ShortChannelID: NewShortChanIDFromInt(
uint64(r.Int63()),
),
NodeID1: randRawKey(t),
NodeID2: randRawKey(t),
BitcoinKey1: randRawKey(t),
BitcoinKey2: randRawKey(t),
Features: randRawFeatureVector(r),
ExtraOpaqueData: make([]byte, 0),
}
@ -1005,26 +1031,6 @@ func TestLightningWireProtocol(t *testing.T) {
return
}
req.NodeID1, err = randRawKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.NodeID2, err = randRawKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.BitcoinKey1, err = randRawKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.BitcoinKey2, err = randRawKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
if _, err := r.Read(req.ChainHash[:]); err != nil {
t.Fatalf("unable to generate chain hash: %v", err)
return
@ -1046,6 +1052,7 @@ func TestLightningWireProtocol(t *testing.T) {
MsgNodeAnnouncement: func(v []reflect.Value, r *rand.Rand) {
var err error
req := NodeAnnouncement{
NodeID: randRawKey(t),
Features: randRawFeatureVector(r),
Timestamp: uint32(r.Int31()),
Alias: randAlias(r),
@ -1062,12 +1069,6 @@ func TestLightningWireProtocol(t *testing.T) {
return
}
req.NodeID, err = randRawKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.Addresses, err = randAddrs(r)
if err != nil {
t.Fatalf("unable to generate addresses: %v", err)
@ -1100,8 +1101,10 @@ func TestLightningWireProtocol(t *testing.T) {
maxHtlc = 0
}
req := ChannelUpdate{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
req := ChannelUpdate1{
ShortChannelID: NewShortChanIDFromInt(
uint64(r.Int63()),
),
Timestamp: uint32(r.Int31()),
MessageFlags: msgFlags,
ChannelFlags: ChanUpdateChanFlags(r.Int31()),
@ -1138,7 +1141,7 @@ func TestLightningWireProtocol(t *testing.T) {
},
MsgAnnounceSignatures: func(v []reflect.Value, r *rand.Rand) {
var err error
req := AnnounceSignatures{
req := AnnounceSignatures1{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
ExtraOpaqueData: make([]byte, 0),
}
@ -1202,6 +1205,35 @@ func TestLightningWireProtocol(t *testing.T) {
v[0] = reflect.ValueOf(req)
},
MsgGossipTimestampRange: func(v []reflect.Value, r *rand.Rand) {
req := GossipTimestampRange{
FirstTimestamp: rand.Uint32(),
TimestampRange: rand.Uint32(),
ExtraData: make([]byte, 0),
}
_, err := rand.Read(req.ChainHash[:])
require.NoError(t, err)
// Sometimes add a block range.
if r.Int31()%2 == 0 {
firstBlock := tlv.ZeroRecordT[
tlv.TlvType2, uint32,
]()
firstBlock.Val = rand.Uint32()
req.FirstBlockHeight = tlv.SomeRecordT(
firstBlock,
)
blockRange := tlv.ZeroRecordT[
tlv.TlvType4, uint32,
]()
blockRange.Val = rand.Uint32()
req.BlockRange = tlv.SomeRecordT(blockRange)
}
v[0] = reflect.ValueOf(req)
},
MsgQueryShortChanIDs: func(v []reflect.Value, r *rand.Rand) {
req := QueryShortChanIDs{
ExtraData: make([]byte, 0),
@ -1467,6 +1499,176 @@ func TestLightningWireProtocol(t *testing.T) {
v[0] = reflect.ValueOf(*req)
},
MsgAnnounceSignatures2: func(v []reflect.Value,
r *rand.Rand) {
req := AnnounceSignatures2{
ShortChannelID: NewShortChanIDFromInt(
uint64(r.Int63()),
),
ExtraOpaqueData: make([]byte, 0),
}
_, err := r.Read(req.ChannelID[:])
require.NoError(t, err)
partialSig, err := randPartialSig(r)
require.NoError(t, err)
req.PartialSignature = *partialSig
numExtraBytes := r.Int31n(1000)
if numExtraBytes > 0 {
req.ExtraOpaqueData = make(
[]byte, numExtraBytes,
)
_, err := r.Read(req.ExtraOpaqueData[:])
require.NoError(t, err)
}
v[0] = reflect.ValueOf(req)
},
MsgChannelAnnouncement2: func(v []reflect.Value, r *rand.Rand) {
req := ChannelAnnouncement2{
Signature: testSchnorrSig,
ExtraOpaqueData: make([]byte, 0),
}
req.ShortChannelID.Val = NewShortChanIDFromInt(
uint64(r.Int63()),
)
req.Capacity.Val = rand.Uint64()
req.Features.Val = *randRawFeatureVector(r)
req.NodeID1.Val = randRawKey(t)
req.NodeID2.Val = randRawKey(t)
// Sometimes set chain hash to bitcoin mainnet genesis
// hash.
req.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if r.Int31()%2 == 0 {
_, err := r.Read(req.ChainHash.Val[:])
require.NoError(t, err)
}
// Sometimes set the bitcoin keys.
if r.Int31()%2 == 0 {
btcKey1 := tlv.ZeroRecordT[
tlv.TlvType12, [33]byte,
]()
btcKey1.Val = randRawKey(t)
req.BitcoinKey1 = tlv.SomeRecordT(btcKey1)
btcKey2 := tlv.ZeroRecordT[
tlv.TlvType14, [33]byte,
]()
btcKey2.Val = randRawKey(t)
req.BitcoinKey2 = tlv.SomeRecordT(btcKey2)
// Occasionally also set the merkle root hash.
if r.Int31()%2 == 0 {
hash := tlv.ZeroRecordT[
tlv.TlvType16, [32]byte,
]()
_, err := r.Read(hash.Val[:])
require.NoError(t, err)
req.MerkleRootHash = tlv.SomeRecordT(
hash,
)
}
}
numExtraBytes := r.Int31n(1000)
if numExtraBytes > 0 {
req.ExtraOpaqueData = make(
[]byte, numExtraBytes,
)
_, err := r.Read(req.ExtraOpaqueData[:])
require.NoError(t, err)
}
v[0] = reflect.ValueOf(req)
},
MsgChannelUpdate2: func(v []reflect.Value, r *rand.Rand) {
req := ChannelUpdate2{
Signature: testSchnorrSig,
ExtraOpaqueData: make([]byte, 0),
}
req.ShortChannelID.Val = NewShortChanIDFromInt(
uint64(r.Int63()),
)
req.BlockHeight.Val = r.Uint32()
req.HTLCMaximumMsat.Val = MilliSatoshi(r.Uint64())
// Sometimes set chain hash to bitcoin mainnet genesis
// hash.
req.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if r.Int31()%2 == 0 {
_, err := r.Read(req.ChainHash.Val[:])
require.NoError(t, err)
}
// Sometimes use default htlc min msat.
req.HTLCMinimumMsat.Val = defaultHtlcMinMsat
if r.Int31()%2 == 0 {
req.HTLCMinimumMsat.Val = MilliSatoshi(
r.Uint64(),
)
}
// Sometimes set the cltv expiry delta to the default.
req.CLTVExpiryDelta.Val = defaultCltvExpiryDelta
if r.Int31()%2 == 0 {
req.CLTVExpiryDelta.Val = uint16(r.Int31())
}
// Sometimes use default fee base.
req.FeeBaseMsat.Val = defaultFeeBaseMsat
if r.Int31()%2 == 0 {
req.FeeBaseMsat.Val = r.Uint32()
}
// Sometimes use default proportional fee.
req.FeeProportionalMillionths.Val =
defaultFeeProportionalMillionths
if r.Int31()%2 == 0 {
req.FeeProportionalMillionths.Val = r.Uint32()
}
// Alternate between the two direction possibilities.
if r.Int31()%2 == 0 {
req.SecondPeer = tlv.SomeRecordT(
tlv.ZeroRecordT[tlv.TlvType8, TrueBoolean](), //nolint:lll
)
}
// Sometimes set the incoming disabled flag.
if r.Int31()%2 == 0 {
req.DisabledFlags.Val |=
ChanUpdateDisableIncoming
}
// Sometimes set the outgoing disabled flag.
if r.Int31()%2 == 0 {
req.DisabledFlags.Val |=
ChanUpdateDisableOutgoing
}
numExtraBytes := r.Int31n(1000)
if numExtraBytes > 0 {
req.ExtraOpaqueData = make(
[]byte, numExtraBytes,
)
_, err := r.Read(req.ExtraOpaqueData[:])
require.NoError(t, err)
}
v[0] = reflect.ValueOf(req)
},
}
// With the above types defined, we'll now generate a slice of
@ -1631,7 +1833,7 @@ func TestLightningWireProtocol(t *testing.T) {
},
{
msgType: MsgChannelAnnouncement,
scenario: func(m ChannelAnnouncement) bool {
scenario: func(m ChannelAnnouncement1) bool {
return mainScenario(&m)
},
},
@ -1643,13 +1845,13 @@ func TestLightningWireProtocol(t *testing.T) {
},
{
msgType: MsgChannelUpdate,
scenario: func(m ChannelUpdate) bool {
scenario: func(m ChannelUpdate1) bool {
return mainScenario(&m)
},
},
{
msgType: MsgAnnounceSignatures,
scenario: func(m AnnounceSignatures) bool {
scenario: func(m AnnounceSignatures1) bool {
return mainScenario(&m)
},
},
@ -1695,6 +1897,24 @@ func TestLightningWireProtocol(t *testing.T) {
return mainScenario(&m)
},
},
{
msgType: MsgAnnounceSignatures2,
scenario: func(m AnnounceSignatures2) bool {
return mainScenario(&m)
},
},
{
msgType: MsgChannelAnnouncement2,
scenario: func(m ChannelAnnouncement2) bool {
return mainScenario(&m)
},
},
{
msgType: MsgChannelUpdate2,
scenario: func(m ChannelUpdate2) bool {
return mainScenario(&m)
},
},
}
for _, test := range tests {
var config *quick.Config

View file

@ -52,11 +52,14 @@ const (
MsgNodeAnnouncement = 257
MsgChannelUpdate = 258
MsgAnnounceSignatures = 259
MsgAnnounceSignatures2 = 260
MsgQueryShortChanIDs = 261
MsgReplyShortChanIDsEnd = 262
MsgQueryChannelRange = 263
MsgReplyChannelRange = 264
MsgGossipTimestampRange = 265
MsgChannelAnnouncement2 = 267
MsgChannelUpdate2 = 271
MsgKickoffSig = 777
)
@ -155,6 +158,12 @@ func (t MessageType) String() string {
return "ClosingComplete"
case MsgClosingSig:
return "ClosingSig"
case MsgAnnounceSignatures2:
return "MsgAnnounceSignatures2"
case MsgChannelAnnouncement2:
return "ChannelAnnouncement2"
case MsgChannelUpdate2:
return "ChannelUpdate2"
default:
return "<unknown>"
}
@ -259,15 +268,15 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
case MsgError:
msg = &Error{}
case MsgChannelAnnouncement:
msg = &ChannelAnnouncement{}
msg = &ChannelAnnouncement1{}
case MsgChannelUpdate:
msg = &ChannelUpdate{}
msg = &ChannelUpdate1{}
case MsgNodeAnnouncement:
msg = &NodeAnnouncement{}
case MsgPing:
msg = &Ping{}
case MsgAnnounceSignatures:
msg = &AnnounceSignatures{}
msg = &AnnounceSignatures1{}
case MsgPong:
msg = &Pong{}
case MsgQueryShortChanIDs:
@ -284,6 +293,12 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
msg = &ClosingComplete{}
case MsgClosingSig:
msg = &ClosingSig{}
case MsgAnnounceSignatures2:
msg = &AnnounceSignatures2{}
case MsgChannelAnnouncement2:
msg = &ChannelAnnouncement2{}
case MsgChannelUpdate2:
msg = &ChannelUpdate2{}
default:
// If the message is not within our custom range and has not
// specifically been overridden, return an unknown message.

View file

@ -645,11 +645,11 @@ func newMsgChannelReestablish(t testing.TB,
}
func newMsgChannelAnnouncement(t testing.TB,
r *rand.Rand) *lnwire.ChannelAnnouncement {
r *rand.Rand) *lnwire.ChannelAnnouncement1 {
t.Helper()
msg := &lnwire.ChannelAnnouncement{
msg := &lnwire.ChannelAnnouncement1{
ShortChannelID: lnwire.NewShortChanIDFromInt(uint64(r.Int63())),
Features: rawFeatureVector(),
NodeID1: randRawKey(t),
@ -692,7 +692,7 @@ func newMsgNodeAnnouncement(t testing.TB,
return msg
}
func newMsgChannelUpdate(t testing.TB, r *rand.Rand) *lnwire.ChannelUpdate {
func newMsgChannelUpdate(t testing.TB, r *rand.Rand) *lnwire.ChannelUpdate1 {
t.Helper()
msgFlags := lnwire.ChanUpdateMsgFlags(r.Int31())
@ -706,7 +706,7 @@ func newMsgChannelUpdate(t testing.TB, r *rand.Rand) *lnwire.ChannelUpdate {
maxHtlc = 0
}
msg := &lnwire.ChannelUpdate{
msg := &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(r.Uint64()),
Timestamp: uint32(r.Int31()),
MessageFlags: msgFlags,
@ -727,11 +727,11 @@ func newMsgChannelUpdate(t testing.TB, r *rand.Rand) *lnwire.ChannelUpdate {
}
func newMsgAnnounceSignatures(t testing.TB,
r *rand.Rand) *lnwire.AnnounceSignatures {
r *rand.Rand) *lnwire.AnnounceSignatures1 {
t.Helper()
msg := &lnwire.AnnounceSignatures{
msg := &lnwire.AnnounceSignatures1{
ShortChannelID: lnwire.NewShortChanIDFromInt(
uint64(r.Int63()),
),

View file

@ -2,8 +2,10 @@ package lnwire
import (
"fmt"
"io"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/tlv"
)
const (
@ -49,3 +51,40 @@ func (m MilliSatoshi) String() string {
}
// TODO(roasbeef): extend with arithmetic operations?
// Record returns a TLV record that can be used to encode/decode a MilliSatoshi
// to/from a TLV stream.
func (m *MilliSatoshi) Record() tlv.Record {
return tlv.MakeDynamicRecord(
0, m, tlv.SizeBigSize(m), encodeMilliSatoshis,
decodeMilliSatoshis,
)
}
func encodeMilliSatoshis(w io.Writer, val interface{}, buf *[8]byte) error {
if v, ok := val.(*MilliSatoshi); ok {
bigSize := uint64(*v)
return tlv.EBigSize(w, &bigSize, buf)
}
return tlv.NewTypeForEncodingErr(val, "lnwire.MilliSatoshi")
}
func decodeMilliSatoshis(r io.Reader, val interface{}, buf *[8]byte,
l uint64) error {
if v, ok := val.(*MilliSatoshi); ok {
var bigSize uint64
err := tlv.DBigSize(r, &bigSize, buf, l)
if err != nil {
return err
}
*v = MilliSatoshi(bigSize)
return nil
}
return tlv.NewTypeForDecodingErr(val, "lnwire.MilliSatoshi", l, l)
}

View file

@ -601,7 +601,7 @@ func (f *FailInvalidOnionKey) Error() string {
// unable to pull out a fully valid version, then we'll fall back to the
// regular parsing mechanism which includes the length prefix an NO type byte.
func parseChannelUpdateCompatibilityMode(reader io.Reader, length uint16,
chanUpdate *ChannelUpdate, pver uint32) error {
chanUpdate *ChannelUpdate1, pver uint32) error {
// Instantiate a LimitReader because there may be additional data
// present after the channel update. Without limiting the stream, the
@ -648,11 +648,13 @@ type FailTemporaryChannelFailure struct {
// which caused the failure.
//
// NOTE: This field is optional.
Update *ChannelUpdate
Update *ChannelUpdate1
}
// NewTemporaryChannelFailure creates new instance of the FailTemporaryChannelFailure.
func NewTemporaryChannelFailure(update *ChannelUpdate) *FailTemporaryChannelFailure {
func NewTemporaryChannelFailure(
update *ChannelUpdate1) *FailTemporaryChannelFailure {
return &FailTemporaryChannelFailure{Update: update}
}
@ -686,7 +688,7 @@ func (f *FailTemporaryChannelFailure) Decode(r io.Reader, pver uint32) error {
}
if length != 0 {
f.Update = &ChannelUpdate{}
f.Update = &ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, f.Update, pver,
@ -721,12 +723,12 @@ type FailAmountBelowMinimum struct {
// Update is used to update information about state of the channel
// which caused the failure.
Update ChannelUpdate
Update ChannelUpdate1
}
// NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum.
func NewAmountBelowMinimum(htlcMsat MilliSatoshi,
update ChannelUpdate) *FailAmountBelowMinimum {
update ChannelUpdate1) *FailAmountBelowMinimum {
return &FailAmountBelowMinimum{
HtlcMsat: htlcMsat,
@ -762,7 +764,7 @@ func (f *FailAmountBelowMinimum) Decode(r io.Reader, pver uint32) error {
return err
}
f.Update = ChannelUpdate{}
f.Update = ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, &f.Update, pver,
@ -791,12 +793,12 @@ type FailFeeInsufficient struct {
// Update is used to update information about state of the channel
// which caused the failure.
Update ChannelUpdate
Update ChannelUpdate1
}
// NewFeeInsufficient creates new instance of the FailFeeInsufficient.
func NewFeeInsufficient(htlcMsat MilliSatoshi,
update ChannelUpdate) *FailFeeInsufficient {
update ChannelUpdate1) *FailFeeInsufficient {
return &FailFeeInsufficient{
HtlcMsat: htlcMsat,
Update: update,
@ -831,7 +833,7 @@ func (f *FailFeeInsufficient) Decode(r io.Reader, pver uint32) error {
return err
}
f.Update = ChannelUpdate{}
f.Update = ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, &f.Update, pver,
@ -862,12 +864,12 @@ type FailIncorrectCltvExpiry struct {
// Update is used to update information about state of the channel
// which caused the failure.
Update ChannelUpdate
Update ChannelUpdate1
}
// NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry.
func NewIncorrectCltvExpiry(cltvExpiry uint32,
update ChannelUpdate) *FailIncorrectCltvExpiry {
update ChannelUpdate1) *FailIncorrectCltvExpiry {
return &FailIncorrectCltvExpiry{
CltvExpiry: cltvExpiry,
@ -900,7 +902,7 @@ func (f *FailIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error {
return err
}
f.Update = ChannelUpdate{}
f.Update = ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, &f.Update, pver,
@ -925,11 +927,11 @@ func (f *FailIncorrectCltvExpiry) Encode(w *bytes.Buffer, pver uint32) error {
type FailExpiryTooSoon struct {
// Update is used to update information about state of the channel
// which caused the failure.
Update ChannelUpdate
Update ChannelUpdate1
}
// NewExpiryTooSoon creates new instance of the FailExpiryTooSoon.
func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon {
func NewExpiryTooSoon(update ChannelUpdate1) *FailExpiryTooSoon {
return &FailExpiryTooSoon{
Update: update,
}
@ -958,7 +960,7 @@ func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error {
return err
}
f.Update = ChannelUpdate{}
f.Update = ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, &f.Update, pver,
@ -984,11 +986,13 @@ type FailChannelDisabled struct {
// Update is used to update information about state of the channel
// which caused the failure.
Update ChannelUpdate
Update ChannelUpdate1
}
// NewChannelDisabled creates new instance of the FailChannelDisabled.
func NewChannelDisabled(flags uint16, update ChannelUpdate) *FailChannelDisabled {
func NewChannelDisabled(flags uint16,
update ChannelUpdate1) *FailChannelDisabled {
return &FailChannelDisabled{
Flags: flags,
Update: update,
@ -1023,7 +1027,7 @@ func (f *FailChannelDisabled) Decode(r io.Reader, pver uint32) error {
return err
}
f.Update = ChannelUpdate{}
f.Update = ChannelUpdate1{}
return parseChannelUpdateCompatibilityMode(
r, length, &f.Update, pver,
@ -1516,7 +1520,7 @@ func makeEmptyOnionError(code FailCode) (FailureMessage, error) {
// writeOnionErrorChanUpdate writes out a ChannelUpdate using the onion error
// format. The format is that we first write out the true serialized length of
// the channel update, followed by the serialized channel update itself.
func writeOnionErrorChanUpdate(w *bytes.Buffer, chanUpdate *ChannelUpdate,
func writeOnionErrorChanUpdate(w *bytes.Buffer, chanUpdate *ChannelUpdate1,
pver uint32) error {
// First, we encode the channel update in a temporary buffer in order

View file

@ -21,7 +21,7 @@ var (
testType = uint64(3)
testOffset = uint16(24)
sig, _ = NewSigFromSignature(testSig)
testChannelUpdate = ChannelUpdate{
testChannelUpdate = ChannelUpdate1{
Signature: sig,
ShortChannelID: NewShortChanIDFromInt(1),
Timestamp: 1,
@ -138,7 +138,7 @@ func TestChannelUpdateCompatibilityParsing(t *testing.T) {
// Now that we have the set of bytes encoded, we'll ensure that we're
// able to decode it using our compatibility method, as it's a regular
// encoded channel update message.
var newChanUpdate ChannelUpdate
var newChanUpdate ChannelUpdate1
err := parseChannelUpdateCompatibilityMode(
&b, uint16(b.Len()), &newChanUpdate, 0,
)
@ -165,7 +165,7 @@ func TestChannelUpdateCompatibilityParsing(t *testing.T) {
// We should be able to properly parse the encoded channel update
// message even with the extra two bytes.
var newChanUpdate2 ChannelUpdate
var newChanUpdate2 ChannelUpdate1
err = parseChannelUpdateCompatibilityMode(
&b, uint16(b.Len()), &newChanUpdate2, 0,
)

View file

@ -60,7 +60,7 @@ type ChanStatusConfig struct {
// ApplyChannelUpdate processes new ChannelUpdates signed by our node by
// updating our local routing table and broadcasting the update to our
// peers.
ApplyChannelUpdate func(*lnwire.ChannelUpdate, *wire.OutPoint,
ApplyChannelUpdate func(*lnwire.ChannelUpdate1, *wire.OutPoint,
bool) error
// DB stores the set of channels that are to be monitored.
@ -650,7 +650,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint,
// in case our ChannelEdgePolicy is not found in the database. Also returns if
// the channel is private by checking AuthProof for nil.
func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) (
*lnwire.ChannelUpdate, bool, error) {
*lnwire.ChannelUpdate1, bool, error) {
// Get the edge info and policies for this channel from the graph.
info, edge1, edge2, err := m.cfg.Graph.FetchChannelEdgesByOutpoint(&op)

View file

@ -126,7 +126,7 @@ type mockGraph struct {
chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy
sidToCid map[lnwire.ShortChannelID]wire.OutPoint
updates chan *lnwire.ChannelUpdate
updates chan *lnwire.ChannelUpdate1
}
func newMockGraph(t *testing.T, numChannels int,
@ -138,7 +138,7 @@ func newMockGraph(t *testing.T, numChannels int,
chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy),
chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy),
sidToCid: make(map[lnwire.ShortChannelID]wire.OutPoint),
updates: make(chan *lnwire.ChannelUpdate, 2*numChannels),
updates: make(chan *lnwire.ChannelUpdate1, 2*numChannels),
}
for i := 0; i < numChannels; i++ {
@ -177,7 +177,7 @@ func (g *mockGraph) FetchChannelEdgesByOutpoint(
return info, pol1, pol2, nil
}
func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate,
func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate1,
op *wire.OutPoint, private bool) error {
g.mu.Lock()

View file

@ -2,9 +2,30 @@ package netann
import (
"bytes"
"errors"
"fmt"
"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/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)
const (
// chanAnn2MsgName is a string representing the name of the
// ChannelAnnouncement2 message. This string will be used during the
// construction of the tagged hash message to be signed when producing
// the signature for the ChannelAnnouncement2 message.
chanAnn2MsgName = "channel_announcement_2"
// chanAnn2SigFieldName is the name of the signature field of the
// ChannelAnnouncement2 message. This string will be used during the
// construction of the tagged hash message to be signed when producing
// the signature for the ChannelAnnouncement2 message.
chanAnn2SigFieldName = "signature"
)
// CreateChanAnnouncement is a helper function which creates all channel
@ -14,14 +35,14 @@ import (
// peer's initial routing table upon connect.
func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
chanInfo *models.ChannelEdgeInfo,
e1, e2 *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement,
*lnwire.ChannelUpdate, *lnwire.ChannelUpdate, error) {
e1, e2 *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1,
*lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) {
// First, using the parameters of the channel, along with the channel
// authentication chanProof, we'll create re-create the original
// authenticated channel announcement.
chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
chanAnn := &lnwire.ChannelAnnouncement{
chanAnn := &lnwire.ChannelAnnouncement1{
ShortChannelID: chanID,
NodeID1: chanInfo.NodeKey1Bytes,
NodeID2: chanInfo.NodeKey2Bytes,
@ -68,7 +89,7 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
// Since it's up to a node's policy as to whether they advertise the
// edge in a direction, we don't create an advertisement if the edge is
// nil.
var edge1Ann, edge2Ann *lnwire.ChannelUpdate
var edge1Ann, edge2Ann *lnwire.ChannelUpdate1
if e1 != nil {
edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1)
if err != nil {
@ -84,3 +105,187 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
return chanAnn, edge1Ann, edge2Ann, nil
}
// 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)
// ValidateChannelAnn validates the channel announcement.
func ValidateChannelAnn(a lnwire.ChannelAnnouncement,
fetchPkScript FetchPkScript) error {
switch ann := a.(type) {
case *lnwire.ChannelAnnouncement1:
return validateChannelAnn1(ann)
case *lnwire.ChannelAnnouncement2:
return validateChannelAnn2(ann, fetchPkScript)
default:
return fmt.Errorf("unhandled implementation of "+
"lnwire.ChannelAnnouncement: %T", a)
}
}
// validateChannelAnn1 validates the channel announcement message and checks
// that node signatures covers the announcement message, and that the bitcoin
// signatures covers the node keys.
func validateChannelAnn1(a *lnwire.ChannelAnnouncement1) error {
// First, we'll compute the digest (h) which is to be signed by each of
// the keys included within the node announcement message. This hash
// digest includes all the keys, so the (up to 4 signatures) will
// attest to the validity of each of the keys.
data, err := a.DataToSign()
if err != nil {
return err
}
dataHash := chainhash.DoubleHashB(data)
// First we'll verify that the passed bitcoin key signature is indeed a
// signature over the computed hash digest.
bitcoinSig1, err := a.BitcoinSig1.ToSignature()
if err != nil {
return err
}
bitcoinKey1, err := btcec.ParsePubKey(a.BitcoinKey1[:])
if err != nil {
return err
}
if !bitcoinSig1.Verify(dataHash, bitcoinKey1) {
return errors.New("can't verify first bitcoin signature")
}
// If that checks out, then we'll verify that the second bitcoin
// signature is a valid signature of the bitcoin public key over hash
// digest as well.
bitcoinSig2, err := a.BitcoinSig2.ToSignature()
if err != nil {
return err
}
bitcoinKey2, err := btcec.ParsePubKey(a.BitcoinKey2[:])
if err != nil {
return err
}
if !bitcoinSig2.Verify(dataHash, bitcoinKey2) {
return errors.New("can't verify second bitcoin signature")
}
// Both node signatures attached should indeed be a valid signature
// over the selected digest of the channel announcement signature.
nodeSig1, err := a.NodeSig1.ToSignature()
if err != nil {
return err
}
nodeKey1, err := btcec.ParsePubKey(a.NodeID1[:])
if err != nil {
return err
}
if !nodeSig1.Verify(dataHash, nodeKey1) {
return errors.New("can't verify data in first node signature")
}
nodeSig2, err := a.NodeSig2.ToSignature()
if err != nil {
return err
}
nodeKey2, err := btcec.ParsePubKey(a.NodeID2[:])
if err != nil {
return err
}
if !nodeSig2.Verify(dataHash, nodeKey2) {
return errors.New("can't verify data in second node signature")
}
return nil
}
// validateChannelAnn2 validates the channel announcement message and checks
// that message signature covers the announcement message.
func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,
fetchPkScript FetchPkScript) error {
dataHash, err := ChanAnn2DigestToSign(a)
if err != nil {
return err
}
sig, err := a.Signature.ToSignature()
if err != nil {
return err
}
nodeKey1, err := btcec.ParsePubKey(a.NodeID1.Val[:])
if err != nil {
return err
}
nodeKey2, err := btcec.ParsePubKey(a.NodeID2.Val[:])
if err != nil {
return err
}
keys := []*btcec.PublicKey{
nodeKey1, nodeKey2,
}
// If the bitcoin keys are provided in the announcement, then it is
// assumed that the signature of the announcement is a 4-of-4 MuSig2
// over the bitcoin keys and node ID keys.
if a.BitcoinKey1.IsSome() && a.BitcoinKey2.IsSome() {
var (
btcKey1 tlv.RecordT[tlv.TlvType12, [33]byte]
btcKey2 tlv.RecordT[tlv.TlvType14, [33]byte]
)
btcKey1 = a.BitcoinKey1.UnwrapOr(btcKey1)
btcKey2 = a.BitcoinKey2.UnwrapOr(btcKey2)
bitcoinKey1, err := btcec.ParsePubKey(btcKey1.Val[:])
if err != nil {
return err
}
bitcoinKey2, err := btcec.ParsePubKey(btcKey2.Val[:])
if err != nil {
return 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 err != nil {
return 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
}
// ChanAnn2DigestToSign computes the digest of the message to be signed.
func ChanAnn2DigestToSign(a *lnwire.ChannelAnnouncement2) (*chainhash.Hash,
error) {
data, err := a.DataToSign()
if err != nil {
return nil, err
}
return MsgHash(chanAnn2MsgName, chanAnn2SigFieldName, data), nil
}

View file

@ -4,11 +4,16 @@ import (
"bytes"
"testing"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -24,7 +29,7 @@ func TestCreateChanAnnouncement(t *testing.T) {
t.Fatalf("unable to encode features: %v", err)
}
expChanAnn := &lnwire.ChannelAnnouncement{
expChanAnn := &lnwire.ChannelAnnouncement1{
ChainHash: chainhash.Hash{0x1},
ShortChannelID: lnwire.ShortChannelID{BlockHeight: 1},
NodeID1: key,
@ -64,3 +69,291 @@ func TestCreateChanAnnouncement(t *testing.T) {
assert.Equal(t, chanAnn, expChanAnn)
}
// TestChanAnnounce2Validation checks that the various forms of the
// channel_announcement_2 message are validated correctly.
func TestChanAnnounce2Validation(t *testing.T) {
t.Parallel()
t.Run(
"test 4-of-4 MuSig2 channel announcement",
test4of4MuSig2ChanAnnouncement,
)
t.Run(
"test 3-of-3 MuSig2 channel announcement",
test3of3MuSig2ChanAnnouncement,
)
}
// test4of4MuSig2ChanAnnouncement covers the case where both bitcoin keys are
// present in the channel announcement. In this case, the signature should be
// a 4-of-4 MuSig2.
func test4of4MuSig2ChanAnnouncement(t *testing.T) {
t.Parallel()
// Generate the keys for node 1 and node2.
node1, node2 := genChanAnnKeys(t)
// Build the unsigned channel announcement.
ann := buildUnsignedChanAnnouncement(node1, node2, true)
// Serialise the bytes that need to be signed.
msg, err := ChanAnn2DigestToSign(ann)
require.NoError(t, err)
var msgBytes [32]byte
copy(msgBytes[:], msg.CloneBytes())
// Generate the 4 nonces required for producing the signature.
var (
node1NodeNonce = genNonceForPubKey(t, node1.nodePub)
node1BtcNonce = genNonceForPubKey(t, node1.btcPub)
node2NodeNonce = genNonceForPubKey(t, node2.nodePub)
node2BtcNonce = genNonceForPubKey(t, node2.btcPub)
)
nonceAgg, err := musig2.AggregateNonces([][66]byte{
node1NodeNonce.PubNonce,
node1BtcNonce.PubNonce,
node2NodeNonce.PubNonce,
node2BtcNonce.PubNonce,
})
require.NoError(t, err)
pubKeys := []*btcec.PublicKey{
node1.nodePub, node2.nodePub, node1.btcPub, node2.btcPub,
}
// Let Node1 sign the announcement message with its node key.
psA1, err := musig2.Sign(
node1NodeNonce.SecNonce, node1.nodePriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Let Node1 sign the announcement message with its bitcoin key.
psA2, err := musig2.Sign(
node1BtcNonce.SecNonce, node1.btcPriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Let Node2 sign the announcement message with its node key.
psB1, err := musig2.Sign(
node2NodeNonce.SecNonce, node2.nodePriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Let Node2 sign the announcement message with its bitcoin key.
psB2, err := musig2.Sign(
node2BtcNonce.SecNonce, node2.btcPriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Finally, combine the partial signatures from Node1 and Node2 and add
// the signature to the announcement message.
s := musig2.CombineSigs(psA1.R, []*musig2.PartialSignature{
psA1, psA2, psB1, psB2,
})
sig, err := lnwire.NewSigFromSignature(s)
require.NoError(t, err)
ann.Signature = sig
// Validate the announcement.
require.NoError(t, ValidateChannelAnn(ann, nil))
}
// test3of3MuSig2ChanAnnouncement covers the case where no bitcoin keys are
// present in the channel announcement. In this case, the signature should be
// a 3-of-3 MuSig2 where the keys making up the pub key are: node1 ID, node2 ID
// and the output key found on-chain in the funding transaction. As the
// verifier, we don't care about the construction of the output key. We only
// care that the channel peers were able to sign for the output key. In reality,
// this key will likely be constructed from at least 1 key from each peer and
// the partial signature for it will be constructed via nested MuSig2 but for
// the sake of the test, we will just have it be backed by a single key.
func test3of3MuSig2ChanAnnouncement(t *testing.T) {
// Generate the keys for node 1 and node 2.
node1, node2 := genChanAnnKeys(t)
// Build the unsigned channel announcement.
ann := buildUnsignedChanAnnouncement(node1, node2, false)
// Serialise the bytes that need to be signed.
msg, err := ChanAnn2DigestToSign(ann)
require.NoError(t, err)
var msgBytes [32]byte
copy(msgBytes[:], msg.CloneBytes())
// Create a random 3rd key to be used for the output key.
outputKeyPriv, err := btcec.NewPrivateKey()
require.NoError(t, err)
outputKey := outputKeyPriv.PubKey()
// Ensure that the output key has an even Y by negating the private key
// if required.
if outputKey.SerializeCompressed()[0] ==
input.PubKeyFormatCompressedOdd {
outputKeyPriv.Key.Negate()
outputKey = outputKeyPriv.PubKey()
}
// Generate the nonces required for producing the partial signatures.
var (
node1NodeNonce = genNonceForPubKey(t, node1.nodePub)
node2NodeNonce = genNonceForPubKey(t, node2.nodePub)
outputKeyNonce = genNonceForPubKey(t, outputKey)
)
nonceAgg, err := musig2.AggregateNonces([][66]byte{
node1NodeNonce.PubNonce,
node2NodeNonce.PubNonce,
outputKeyNonce.PubNonce,
})
require.NoError(t, err)
pkScript, err := input.PayToTaprootScript(outputKey)
require.NoError(t, err)
// We'll pass in a mock tx fetcher that will return the funding output
// containing this key. This is needed since the output key can not be
// determined from the channel announcement itself.
fetchTx := func(chanID *lnwire.ShortChannelID) ([]byte, error) {
return pkScript, nil
}
pubKeys := []*btcec.PublicKey{node1.nodePub, node2.nodePub, outputKey}
// Let Node1 sign the announcement message with its node key.
psA, err := musig2.Sign(
node1NodeNonce.SecNonce, node1.nodePriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Let Node2 sign the announcement message with its node key.
psB, err := musig2.Sign(
node2NodeNonce.SecNonce, node2.nodePriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Create a partial sig for the output key.
psO, err := musig2.Sign(
outputKeyNonce.SecNonce, outputKeyPriv, nonceAgg, pubKeys,
msgBytes, musig2.WithSortedKeys(),
)
require.NoError(t, err)
// Finally, combine the partial signatures from Node1 and Node2 and add
// the signature to the announcement message.
s := musig2.CombineSigs(psA.R, []*musig2.PartialSignature{
psA, psB, psO,
})
sig, err := lnwire.NewSigFromSignature(s)
require.NoError(t, err)
ann.Signature = sig
// Validate the announcement.
require.NoError(t, ValidateChannelAnn(ann, fetchTx))
}
func genNonceForPubKey(t *testing.T, pub *btcec.PublicKey) *musig2.Nonces {
nonce, err := musig2.GenNonces(musig2.WithPublicKey(pub))
require.NoError(t, err)
return nonce
}
type keyRing struct {
nodePriv *btcec.PrivateKey
nodePub *btcec.PublicKey
btcPriv *btcec.PrivateKey
btcPub *btcec.PublicKey
}
func genChanAnnKeys(t *testing.T) (*keyRing, *keyRing) {
// Let Alice and Bob derive the various keys they need.
aliceNodePrivKey, err := btcec.NewPrivateKey()
require.NoError(t, err)
aliceNodeID := aliceNodePrivKey.PubKey()
aliceBtcPrivKey, err := btcec.NewPrivateKey()
require.NoError(t, err)
bobNodePrivKey, err := btcec.NewPrivateKey()
require.NoError(t, err)
bobNodeID := bobNodePrivKey.PubKey()
bobBtcPrivKey, err := btcec.NewPrivateKey()
require.NoError(t, err)
alice := &keyRing{
nodePriv: aliceNodePrivKey,
nodePub: aliceNodePrivKey.PubKey(),
btcPriv: aliceBtcPrivKey,
btcPub: aliceBtcPrivKey.PubKey(),
}
bob := &keyRing{
nodePriv: bobNodePrivKey,
nodePub: bobNodePrivKey.PubKey(),
btcPriv: bobBtcPrivKey,
btcPub: bobBtcPrivKey.PubKey(),
}
if bytes.Compare(
aliceNodeID.SerializeCompressed(),
bobNodeID.SerializeCompressed(),
) != -1 {
return bob, alice
}
return alice, bob
}
func buildUnsignedChanAnnouncement(node1, node2 *keyRing,
withBtcKeys bool) *lnwire.ChannelAnnouncement2 {
var ann lnwire.ChannelAnnouncement2
ann.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
features := lnwire.NewRawFeatureVector()
ann.Features.Val = *features
ann.ShortChannelID.Val = lnwire.ShortChannelID{
BlockHeight: 1000,
TxIndex: 100,
TxPosition: 0,
}
ann.Capacity.Val = 100000
copy(ann.NodeID1.Val[:], node1.nodePub.SerializeCompressed())
copy(ann.NodeID2.Val[:], node2.nodePub.SerializeCompressed())
if !withBtcKeys {
return &ann
}
btcKey1Bytes := tlv.ZeroRecordT[tlv.TlvType12, [33]byte]()
btcKey2Bytes := tlv.ZeroRecordT[tlv.TlvType14, [33]byte]()
copy(btcKey1Bytes.Val[:], node1.btcPub.SerializeCompressed())
copy(btcKey2Bytes.Val[:], node2.btcPub.SerializeCompressed())
ann.BitcoinKey1 = tlv.SomeRecordT(btcKey1Bytes)
ann.BitcoinKey2 = tlv.SomeRecordT(btcKey2Bytes)
return &ann
}

View file

@ -6,10 +6,28 @@ import (
"time"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/pkg/errors"
)
const (
// chanUpdate2MsgName is a string representing the name of the
// ChannelUpdate2 message. This string will be used during the
// construction of the tagged hash message to be signed when producing
// the signature for the ChannelUpdate2 message.
chanUpdate2MsgName = "channel_update_2"
// chanUpdate2SigField is the name of the signature field of the
// ChannelUpdate2 message. This string will be used during the
// construction of the tagged hash message to be signed when producing
// the signature for the ChannelUpdate2 message.
chanUpdate2SigField = "signature"
)
// ErrUnableToExtractChanUpdate is returned when a channel update cannot be
@ -18,12 +36,12 @@ var ErrUnableToExtractChanUpdate = fmt.Errorf("unable to extract ChannelUpdate")
// ChannelUpdateModifier is a closure that makes in-place modifications to an
// lnwire.ChannelUpdate.
type ChannelUpdateModifier func(*lnwire.ChannelUpdate)
type ChannelUpdateModifier func(*lnwire.ChannelUpdate1)
// ChanUpdSetDisable is a functional option that sets the disabled channel flag
// if disabled is true, and clears the bit otherwise.
func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier {
return func(update *lnwire.ChannelUpdate) {
return func(update *lnwire.ChannelUpdate1) {
if disabled {
// Set the bit responsible for marking a channel as
// disabled.
@ -39,7 +57,7 @@ func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier {
// ChanUpdSetTimestamp is a functional option that sets the timestamp of the
// update to the current time, or increments it if the timestamp is already in
// the future.
func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate1) {
newTimestamp := uint32(time.Now().Unix())
if newTimestamp <= update.Timestamp {
// Increment the prior value to ensure the timestamp
@ -57,7 +75,7 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
//
// NOTE: This method modifies the given update.
func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error {
update *lnwire.ChannelUpdate1, mods ...ChannelUpdateModifier) error {
// Apply the requested changes to the channel update.
for _, modifier := range mods {
@ -86,7 +104,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator
func ExtractChannelUpdate(ownerPubKey []byte,
info *models.ChannelEdgeInfo,
policies ...*models.ChannelEdgePolicy) (
*lnwire.ChannelUpdate, error) {
*lnwire.ChannelUpdate1, error) {
// Helper function to extract the owner of the given policy.
owner := func(edge *models.ChannelEdgePolicy) []byte {
@ -118,9 +136,9 @@ func ExtractChannelUpdate(ownerPubKey []byte,
// UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the
// given edge info and policy.
func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
policy *models.ChannelEdgePolicy) *lnwire.ChannelUpdate {
policy *models.ChannelEdgePolicy) *lnwire.ChannelUpdate1 {
return &lnwire.ChannelUpdate{
return &lnwire.ChannelUpdate1{
ChainHash: info.ChainHash,
ShortChannelID: lnwire.NewShortChanIDFromInt(policy.ChannelID),
Timestamp: uint32(policy.LastUpdate.Unix()),
@ -138,7 +156,7 @@ func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge
// info and policy.
func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
policy *models.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) {
policy *models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) {
update := UnsignedChannelUpdateFromEdge(info, policy)
@ -152,3 +170,165 @@ func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
return update, nil
}
// ValidateChannelUpdateAnn validates the channel update announcement by
// checking (1) that the included signature covers the announcement and has been
// signed by the node's private key, and (2) that the announcement's message
// flags and optional fields are sane.
func ValidateChannelUpdateAnn(pubKey *btcec.PublicKey, capacity btcutil.Amount,
a lnwire.ChannelUpdate) error {
if err := ValidateChannelUpdateFields(capacity, a); err != nil {
return err
}
return VerifyChannelUpdateSignature(a, pubKey)
}
// VerifyChannelUpdateSignature verifies that the channel update message was
// signed by the party with the given node public key.
func VerifyChannelUpdateSignature(msg lnwire.ChannelUpdate,
pubKey *btcec.PublicKey) error {
switch u := msg.(type) {
case *lnwire.ChannelUpdate1:
return verifyChannelUpdate1Signature(u, pubKey)
case *lnwire.ChannelUpdate2:
return verifyChannelUpdate2Signature(u, pubKey)
default:
return fmt.Errorf("unhandled implementation of "+
"lnwire.ChannelUpdate: %T", msg)
}
}
// verifyChannelUpdateSignature1 verifies that the channel update message was
// signed by the party with the given node public key.
func verifyChannelUpdate1Signature(msg *lnwire.ChannelUpdate1,
pubKey *btcec.PublicKey) error {
data, err := msg.DataToSign()
if err != nil {
return fmt.Errorf("unable to reconstruct message data: %w", err)
}
dataHash := chainhash.DoubleHashB(data)
nodeSig, err := msg.Signature.ToSignature()
if err != nil {
return err
}
if !nodeSig.Verify(dataHash, pubKey) {
return fmt.Errorf("invalid signature for channel update %v",
spew.Sdump(msg))
}
return nil
}
// verifyChannelUpdateSignature2 verifies that the channel update message was
// signed by the party with the given node public key.
func verifyChannelUpdate2Signature(c *lnwire.ChannelUpdate2,
pubKey *btcec.PublicKey) error {
digest, err := chanUpdate2DigestToSign(c)
if err != nil {
return fmt.Errorf("unable to reconstruct message data: %w", err)
}
nodeSig, err := c.Signature.ToSignature()
if err != nil {
return err
}
if !nodeSig.Verify(digest, pubKey) {
return fmt.Errorf("invalid signature for channel update %v",
spew.Sdump(c))
}
return nil
}
// ValidateChannelUpdateFields validates a channel update's message flags and
// corresponding update fields.
func ValidateChannelUpdateFields(capacity btcutil.Amount,
msg lnwire.ChannelUpdate) error {
switch u := msg.(type) {
case *lnwire.ChannelUpdate1:
return validateChannelUpdate1Fields(capacity, u)
case *lnwire.ChannelUpdate2:
return validateChannelUpdate2Fields(capacity, u)
default:
return fmt.Errorf("unhandled implementation of "+
"lnwire.ChannelUpdate: %T", msg)
}
}
// validateChannelUpdate1Fields validates a channel update's message flags and
// corresponding update fields.
func validateChannelUpdate1Fields(capacity btcutil.Amount,
msg *lnwire.ChannelUpdate1) error {
// The maxHTLC flag is mandatory.
if !msg.MessageFlags.HasMaxHtlc() {
return errors.Errorf("max htlc flag not set for channel "+
"update %v", spew.Sdump(msg))
}
maxHtlc := msg.HtlcMaximumMsat
if maxHtlc == 0 || maxHtlc < msg.HtlcMinimumMsat {
return errors.Errorf("invalid max htlc for channel "+
"update %v", spew.Sdump(msg))
}
// For light clients, the capacity will not be set so we'll skip
// checking whether the MaxHTLC value respects the channel's
// capacity.
capacityMsat := lnwire.NewMSatFromSatoshis(capacity)
if capacityMsat != 0 && maxHtlc > capacityMsat {
return errors.Errorf("max_htlc (%v) for channel update "+
"greater than capacity (%v)", maxHtlc, capacityMsat)
}
return nil
}
// validateChannelUpdate2Fields validates a channel update's message flags and
// corresponding update fields.
func validateChannelUpdate2Fields(capacity btcutil.Amount,
c *lnwire.ChannelUpdate2) error {
maxHtlc := c.HTLCMaximumMsat.Val
if maxHtlc == 0 || maxHtlc < c.HTLCMinimumMsat.Val {
return fmt.Errorf("invalid max htlc for channel update %v",
spew.Sdump(c))
}
// Checking whether the MaxHTLC value respects the channel's capacity.
capacityMsat := lnwire.NewMSatFromSatoshis(capacity)
if maxHtlc > capacityMsat {
return fmt.Errorf("max_htlc (%v) for channel update greater "+
"than capacity (%v)", maxHtlc, capacityMsat)
}
return nil
}
// ChanUpdate2DigestTag returns the tag to be used when signing the digest of
// a channel_update_2 message.
func ChanUpdate2DigestTag() []byte {
return MsgTag(chanUpdate2MsgName, chanUpdate2SigField)
}
// chanUpdate2DigestToSign computes the digest of the ChannelUpdate2 message to
// be signed.
func chanUpdate2DigestToSign(c *lnwire.ChannelUpdate2) ([]byte, error) {
data, err := c.DataToSign()
if err != nil {
return nil, err
}
hash := MsgHash(chanUpdate2MsgName, chanUpdate2SigField, data)
return hash[:], nil
}

View file

@ -7,7 +7,6 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/lightningnetwork/lnd/graph"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
@ -111,7 +110,7 @@ func TestUpdateDisableFlag(t *testing.T) {
// Create the initial update, the only fields we are
// concerned with in this test are the timestamp and the
// channel flags.
ogUpdate := &lnwire.ChannelUpdate{
ogUpdate := &lnwire.ChannelUpdate1{
Timestamp: uint32(tc.startTime.Unix()),
}
if !tc.startEnabled {
@ -122,7 +121,7 @@ func TestUpdateDisableFlag(t *testing.T) {
// the original. UpdateDisableFlag will mutate the
// passed channel update, so we keep the old one to test
// against.
newUpdate := &lnwire.ChannelUpdate{
newUpdate := &lnwire.ChannelUpdate1{
Timestamp: ogUpdate.Timestamp,
ChannelFlags: ogUpdate.ChannelFlags,
}
@ -182,7 +181,7 @@ func TestUpdateDisableFlag(t *testing.T) {
// Finally, validate the signature using the router's
// verification logic.
err = graph.VerifyChannelUpdateSignature(
err = netann.VerifyChannelUpdateSignature(
newUpdate, pubKey,
)
if err != nil {

30
netann/msg_hash.go Normal file
View file

@ -0,0 +1,30 @@
package netann
import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
// MsgHashTag will prefix the message name and the field name in order to
// construct the message tag.
const MsgHashTag = "lightning"
// MsgTag computes the full tag that will be used to prefix a message before
// calculating the tagged hash. The tag is constructed as follows:
//
// tag = "lightning"||"msg_name"||"field_name"
func MsgTag(msgName, fieldName string) []byte {
tag := []byte(MsgHashTag)
tag = append(tag, []byte(msgName)...)
return append(tag, []byte(fieldName)...)
}
// MsgHash computes the tagged hash of the given message as follows:
//
// tag = "lightning"||"msg_name"||"field_name"
// hash = sha256(sha246(tag) || sha256(tag) || msg)
func MsgHash(msgName, fieldName string, msg []byte) *chainhash.Hash {
tag := MsgTag(msgName, fieldName)
return chainhash.TaggedHash(tag, msg)
}

View file

@ -20,9 +20,9 @@ func SignAnnouncement(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
)
switch m := msg.(type) {
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
data, err = m.DataToSign()
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
data, err = m.DataToSign()
case *lnwire.NodeAnnouncement:
data, err = m.DataToSign()

View file

@ -301,7 +301,7 @@ type Config struct {
// FetchLastChanUpdate fetches our latest channel update for a target
// channel.
FetchLastChanUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate,
FetchLastChanUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate1,
error)
// FundingManager is an implementation of the funding.Controller interface.
@ -1963,10 +1963,10 @@ out:
nextMsg.MsgType())
}
case *lnwire.ChannelUpdate,
*lnwire.ChannelAnnouncement,
case *lnwire.ChannelUpdate1,
*lnwire.ChannelAnnouncement1,
*lnwire.NodeAnnouncement,
*lnwire.AnnounceSignatures,
*lnwire.AnnounceSignatures1,
*lnwire.GossipTimestampRange,
*lnwire.QueryShortChanIDs,
*lnwire.QueryChannelRange,
@ -2225,15 +2225,15 @@ func messageSummary(msg lnwire.Message) string {
case *lnwire.Error:
return fmt.Sprintf("%v", msg.Error())
case *lnwire.AnnounceSignatures:
case *lnwire.AnnounceSignatures1:
return fmt.Sprintf("chan_id=%v, short_chan_id=%v", msg.ChannelID,
msg.ShortChannelID.ToUint64())
case *lnwire.ChannelAnnouncement:
case *lnwire.ChannelAnnouncement1:
return fmt.Sprintf("chain_hash=%v, short_chan_id=%v",
msg.ChainHash, msg.ShortChannelID.ToUint64())
case *lnwire.ChannelUpdate:
case *lnwire.ChannelUpdate1:
return fmt.Sprintf("chain_hash=%v, short_chan_id=%v, "+
"mflags=%v, cflags=%v, update_time=%v", msg.ChainHash,
msg.ShortChannelID.ToUint64(), msg.MessageFlags,

View file

@ -611,7 +611,7 @@ func createTestPeer(t *testing.T) *peerTestCtx {
IsChannelActive: func(lnwire.ChannelID) bool {
return true
},
ApplyChannelUpdate: func(*lnwire.ChannelUpdate,
ApplyChannelUpdate: func(*lnwire.ChannelUpdate1,
*wire.OutPoint, bool) error {
return nil
@ -719,9 +719,9 @@ func createTestPeer(t *testing.T) *peerTestCtx {
},
PongBuf: make([]byte, lnwire.MaxPongBytes),
FetchLastChanUpdate: func(chanID lnwire.ShortChannelID,
) (*lnwire.ChannelUpdate, error) {
) (*lnwire.ChannelUpdate1, error) {
return &lnwire.ChannelUpdate{}, nil
return &lnwire.ChannelUpdate1{}, nil
},
}

View file

@ -197,7 +197,7 @@ func TestMissionControl(t *testing.T) {
// A node level failure should bring probability of all known channels
// back to zero.
ctx.reportFailure(0, lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}))
ctx.reportFailure(0, lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate1{}))
ctx.expectP(1000, 0)
// Check whether history snapshot looks sane.
@ -219,14 +219,14 @@ func TestMissionControlChannelUpdate(t *testing.T) {
// Report a policy related failure. Because it is the first, we don't
// expect a penalty.
ctx.reportFailure(
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate1{}),
)
ctx.expectP(100, testAprioriHopProbability)
// Report another failure for the same channel. We expect it to be
// pruned.
ctx.reportFailure(
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate1{}),
)
ctx.expectP(100, 0)
}

View file

@ -186,7 +186,7 @@ func (m *mockPaymentSessionOld) RequestRoute(_, _ lnwire.MilliSatoshi,
return r, nil
}
func (m *mockPaymentSessionOld) UpdateAdditionalEdge(_ *lnwire.ChannelUpdate,
func (m *mockPaymentSessionOld) UpdateAdditionalEdge(_ *lnwire.ChannelUpdate1,
_ *btcec.PublicKey, _ *models.CachedEdgePolicy) bool {
return false
@ -710,7 +710,7 @@ func (m *mockPaymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
return args.Get(0).(*route.Route), args.Error(1)
}
func (m *mockPaymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate,
func (m *mockPaymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1,
pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool {
args := m.Called(msg, pubKey, policy)

View file

@ -8,9 +8,9 @@ import (
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/graph"
"github.com/lightningnetwork/lnd/lnutils"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/routing/route"
)
@ -147,8 +147,8 @@ type PaymentSession interface {
// (private channels) and applies the update from the message. Returns
// a boolean to indicate whether the update has been applied without
// error.
UpdateAdditionalEdge(msg *lnwire.ChannelUpdate, pubKey *btcec.PublicKey,
policy *models.CachedEdgePolicy) bool
UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1,
pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool
// GetAdditionalEdgePolicy uses the public key and channel ID to query
// the ephemeral channel edge policy for additional edges. Returns a nil
@ -436,11 +436,11 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
// validates the message signature and checks it's up to date, then applies the
// updates to the supplied policy. It returns a boolean to indicate whether
// there's an error when applying the updates.
func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate,
func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1,
pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool {
// Validate the message signature.
if err := graph.VerifyChannelUpdateSignature(msg, pubKey); err != nil {
if err := netann.VerifyChannelUpdateSignature(msg, pubKey); err != nil {
log.Errorf(
"Unable to validate channel update signature: %v", err,
)

View file

@ -147,7 +147,7 @@ func TestUpdateAdditionalEdge(t *testing.T) {
)
// Create the channel update message and sign.
msg := &lnwire.ChannelUpdate{
msg := &lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(testChannelID),
Timestamp: uint32(time.Now().Unix()),
BaseFee: newFeeBaseMSat,

View file

@ -164,7 +164,7 @@ var resultTestCases = []resultTestCase{
name: "fail expiry too soon",
route: &routeFourHop,
failureSrcIdx: 3,
failure: lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}),
failure: lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate1{}),
expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{
@ -266,8 +266,9 @@ var resultTestCases = []resultTestCase{
name: "fail fee insufficient intermediate",
route: &routeFourHop,
failureSrcIdx: 2,
failure: lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),
failure: lnwire.NewFeeInsufficient(
0, lnwire.ChannelUpdate1{},
),
expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): {

View file

@ -288,7 +288,7 @@ type Config struct {
// ApplyChannelUpdate can be called to apply a new channel update to the
// graph that we received from a payment failure.
ApplyChannelUpdate func(msg *lnwire.ChannelUpdate) bool
ApplyChannelUpdate func(msg *lnwire.ChannelUpdate1) bool
// ClosedSCIDs is used by the router to fetch closed channels.
//
@ -1329,9 +1329,9 @@ func (r *ChannelRouter) sendPayment(ctx context.Context,
// extractChannelUpdate examines the error and extracts the channel update.
func (r *ChannelRouter) extractChannelUpdate(
failure lnwire.FailureMessage) *lnwire.ChannelUpdate {
failure lnwire.FailureMessage) *lnwire.ChannelUpdate1 {
var update *lnwire.ChannelUpdate
var update *lnwire.ChannelUpdate1
switch onionErr := failure.(type) {
case *lnwire.FailExpiryTooSoon:
update = &onionErr.Update

View file

@ -223,7 +223,7 @@ func createTestCtxFromFile(t *testing.T,
// Add valid signature to channel update simulated as error received from the
// network.
func signErrChanUpdate(t *testing.T, key *btcec.PrivateKey,
errChanUpdate *lnwire.ChannelUpdate) {
errChanUpdate *lnwire.ChannelUpdate1) {
chanUpdateMsg, err := errChanUpdate.DataToSign()
require.NoError(t, err, "failed to retrieve data to sign")
@ -488,7 +488,7 @@ func TestChannelUpdateValidation(t *testing.T) {
// Set up a channel update message with an invalid signature to be
// returned to the sender.
var invalidSignature lnwire.Sig
errChanUpdate := lnwire.ChannelUpdate{
errChanUpdate := lnwire.ChannelUpdate1{
Signature: invalidSignature,
FeeRate: 500,
ShortChannelID: lnwire.NewShortChanIDFromInt(1),
@ -593,7 +593,7 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
)
require.NoError(t, err, "unable to fetch chan id")
errChanUpdate := lnwire.ChannelUpdate{
errChanUpdate := lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(
songokuSophonChanID,
),
@ -712,7 +712,7 @@ func TestSendPaymentErrorFeeInsufficientPrivateEdge(t *testing.T) {
// Prepare an error update for the private channel, with twice the
// original fee.
updatedFeeBaseMSat := feeBaseMSat * 2
errChanUpdate := lnwire.ChannelUpdate{
errChanUpdate := lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(privateChannelID),
Timestamp: uint32(testTime.Add(time.Minute).Unix()),
BaseFee: updatedFeeBaseMSat,
@ -838,7 +838,7 @@ func TestSendPaymentPrivateEdgeUpdateFeeExceedsLimit(t *testing.T) {
// Prepare an error update for the private channel. The updated fee
// will exceeds the feeLimit.
updatedFeeBaseMSat := feeBaseMSat + uint32(feeLimit)
errChanUpdate := lnwire.ChannelUpdate{
errChanUpdate := lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(privateChannelID),
Timestamp: uint32(testTime.Add(time.Minute).Unix()),
BaseFee: updatedFeeBaseMSat,
@ -939,7 +939,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
_, _, edgeUpdateToFail, err := ctx.graph.FetchChannelEdgesByID(chanID)
require.NoError(t, err, "unable to fetch chan id")
errChanUpdate := lnwire.ChannelUpdate{
errChanUpdate := lnwire.ChannelUpdate1{
ShortChannelID: lnwire.NewShortChanIDFromInt(chanID),
Timestamp: uint32(edgeUpdateToFail.LastUpdate.Unix()),
MessageFlags: edgeUpdateToFail.MessageFlags,
@ -1402,7 +1402,7 @@ func TestSendToRouteStructuredError(t *testing.T) {
testCases := map[int]lnwire.FailureMessage{
finalHopIndex: lnwire.NewFailIncorrectDetails(payAmt, 100),
1: &lnwire.FailFeeInsufficient{
Update: lnwire.ChannelUpdate{},
Update: lnwire.ChannelUpdate1{},
},
}
@ -2967,7 +2967,7 @@ func (m *mockGraphBuilder) setNextReject(reject bool) {
m.rejectUpdate = reject
}
func (m *mockGraphBuilder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate) bool {
func (m *mockGraphBuilder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool {
if m.rejectUpdate {
return false
}

View file

@ -1042,6 +1042,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s.authGossiper = discovery.New(discovery.Config{
Graph: s.graphBuilder,
ChainIO: s.cc.ChainIO,
Notifier: s.cc.ChainNotifier,
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
Broadcast: s.BroadcastMessage,
@ -1753,7 +1754,7 @@ func (s *server) UpdateRoutingConfig(cfg *routing.MissionControlConfig) {
// signAliasUpdate takes a ChannelUpdate and returns the signature. This is
// used for option_scid_alias channels where the ChannelUpdate to be sent back
// may differ from what is on disk.
func (s *server) signAliasUpdate(u *lnwire.ChannelUpdate) (*ecdsa.Signature,
func (s *server) signAliasUpdate(u *lnwire.ChannelUpdate1) (*ecdsa.Signature,
error) {
data, err := u.DataToSign()
@ -4826,10 +4827,10 @@ func (s *server) fetchNodeAdvertisedAddrs(pub *btcec.PublicKey) ([]net.Addr, err
// fetchLastChanUpdate returns a function which is able to retrieve our latest
// channel update for a target channel.
func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
*lnwire.ChannelUpdate, error) {
*lnwire.ChannelUpdate1, error) {
ourPubKey := s.identityECDH.PubKey().SerializeCompressed()
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, error) {
info, edge1, edge2, err := s.graphBuilder.GetChannelByID(cid)
if err != nil {
return nil, err
@ -4844,7 +4845,7 @@ func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
// applyChannelUpdate applies the channel update to the different sub-systems of
// the server. The useAlias boolean denotes whether or not to send an alias in
// place of the real SCID.
func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate,
func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate1,
op *wire.OutPoint, useAlias bool) error {
var (