Merge pull request #706 from Roasbeef/gc-fixes-reject-cache

multi: memoize pubkey+signature decoding to reduce GC bursts, add reject cache to stop zombie churn
This commit is contained in:
Olaoluwa Osuntokun 2018-02-06 20:37:41 -08:00 committed by GitHub
commit 7bbcbc6fea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1627 additions and 942 deletions

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"

@ -63,7 +63,8 @@ var _ Node = (*dbNode)(nil)
// //
// NOTE: Part of the autopilot.Node interface. // NOTE: Part of the autopilot.Node interface.
func (d dbNode) PubKey() *btcec.PublicKey { func (d dbNode) PubKey() *btcec.PublicKey {
return d.node.PubKey pubKey, _ := d.node.PubKey()
return pubKey
} }
// Addrs returns a slice of publicly reachable public TCP addresses that the // Addrs returns a slice of publicly reachable public TCP addresses that the
@ -84,12 +85,13 @@ func (d dbNode) ForEachChannel(cb func(ChannelEdge) error) error {
return d.node.ForEachChannel(d.tx, func(tx *bolt.Tx, return d.node.ForEachChannel(d.tx, func(tx *bolt.Tx,
ei *channeldb.ChannelEdgeInfo, ep, _ *channeldb.ChannelEdgePolicy) error { ei *channeldb.ChannelEdgeInfo, ep, _ *channeldb.ChannelEdgePolicy) error {
pubkey, _ := ep.Node.PubKey()
edge := ChannelEdge{ edge := ChannelEdge{
Channel: Channel{ Channel: Channel{
ChanID: lnwire.NewShortChanIDFromInt(ep.ChannelID), ChanID: lnwire.NewShortChanIDFromInt(ep.ChannelID),
Capacity: ei.Capacity, Capacity: ei.Capacity,
FundedAmt: ei.Capacity, FundedAmt: ei.Capacity,
Node: NewNodeID(ep.Node.PubKey), Node: NewNodeID(pubkey),
}, },
Peer: dbNode{ Peer: dbNode{
tx: tx, tx: tx,
@ -138,7 +140,6 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
fallthrough fallthrough
case err == channeldb.ErrGraphNotFound: case err == channeldb.ErrGraphNotFound:
graphNode := &channeldb.LightningNode{ graphNode := &channeldb.LightningNode{
PubKey: pub,
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
Addresses: []net.Addr{ Addresses: []net.Addr{
&net.TCPAddr{ &net.TCPAddr{
@ -147,8 +148,9 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
}, },
Features: lnwire.NewFeatureVector(nil, Features: lnwire.NewFeatureVector(nil,
lnwire.GlobalFeatures), lnwire.GlobalFeatures),
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
} }
graphNode.AddPubKey(pub)
if err := d.db.AddLightningNode(graphNode); err != nil { if err := d.db.AddLightningNode(graphNode); err != nil {
return nil, err return nil, err
} }
@ -164,16 +166,16 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
return nil, err return nil, err
} }
dbNode := &channeldb.LightningNode{ dbNode := &channeldb.LightningNode{
PubKey: nodeKey,
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
Addresses: []net.Addr{ Addresses: []net.Addr{
&net.TCPAddr{ &net.TCPAddr{
IP: bytes.Repeat([]byte("a"), 16), IP: bytes.Repeat([]byte("a"), 16),
}, },
}, },
Features: lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures), Features: lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures),
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
} }
dbNode.AddPubKey(nodeKey)
if err := d.db.AddLightningNode(dbNode); err != nil { if err := d.db.AddLightningNode(dbNode); err != nil {
return nil, err return nil, err
} }
@ -192,30 +194,25 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
} }
var lnNode1, lnNode2 *btcec.PublicKey var lnNode1, lnNode2 *btcec.PublicKey
node1Bytes := vertex1.PubKey.SerializeCompressed() if bytes.Compare(vertex1.PubKeyBytes[:], vertex2.PubKeyBytes[:]) == -1 {
node2Bytes := vertex2.PubKey.SerializeCompressed() lnNode1, _ = vertex1.PubKey()
if bytes.Compare(node1Bytes, node2Bytes) == -1 { lnNode2, _ = vertex2.PubKey()
lnNode1 = vertex1.PubKey
lnNode2 = vertex2.PubKey
} else { } else {
lnNode1 = vertex2.PubKey lnNode1, _ = vertex2.PubKey()
lnNode2 = vertex1.PubKey lnNode2, _ = vertex1.PubKey()
} }
chanID := randChanID() chanID := randChanID()
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: lnNode1, Capacity: capacity,
NodeKey2: lnNode2,
BitcoinKey1: vertex1.PubKey,
BitcoinKey2: vertex2.PubKey,
Capacity: capacity,
} }
edge.AddNodeKeys(lnNode1, lnNode2, lnNode1, lnNode2)
if err := d.db.AddChannelEdge(edge); err != nil { if err := d.db.AddChannelEdge(edge); err != nil {
return nil, nil, err return nil, nil, err
} }
edgePolicy := &channeldb.ChannelEdgePolicy{ edgePolicy := &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,
@ -229,7 +226,7 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
return nil, nil, err return nil, nil, err
} }
edgePolicy = &channeldb.ChannelEdgePolicy{ edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,

@ -10,7 +10,6 @@ import (
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/txscript" "github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
@ -410,12 +409,12 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
// transaction! We'll craft the final closing transaction so // transaction! We'll craft the final closing transaction so
// we can broadcast it to the network. // we can broadcast it to the network.
matchingSig := c.priorFeeOffers[remoteProposedFee].Signature matchingSig := c.priorFeeOffers[remoteProposedFee].Signature
localSig := append( localSigBytes := matchingSig.ToSignatureBytes()
matchingSig.Serialize(), byte(txscript.SigHashAll), localSig := append(localSigBytes, byte(txscript.SigHashAll))
)
remoteSig := append( remoteSigBytes := closeSignedMsg.Signature.ToSignatureBytes()
closeSignedMsg.Signature.Serialize(), byte(txscript.SigHashAll), remoteSig := append(remoteSigBytes, byte(txscript.SigHashAll))
)
closeTx, finalLocalBalance, err := c.cfg.channel.CompleteCooperativeClose( closeTx, finalLocalBalance, err := c.cfg.channel.CompleteCooperativeClose(
localSig, remoteSig, c.localDeliveryScript, localSig, remoteSig, c.localDeliveryScript,
c.remoteDeliveryScript, remoteProposedFee, c.remoteDeliveryScript, remoteProposedFee,
@ -512,7 +511,7 @@ func (c *channelCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingS
// party responds we'll be able to decide if we've agreed on fees or // party responds we'll be able to decide if we've agreed on fees or
// not. // not.
c.lastFeeProposal = fee c.lastFeeProposal = fee
parsedSig, err := btcec.ParseSignature(rawSig, btcec.S256()) parsedSig, err := lnwire.NewSigFromRawSignature(rawSig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -81,6 +81,8 @@ var (
Index: 0, Index: 0,
} }
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), key[:]) privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), key[:])
wireSig, _ = lnwire.NewSigFromSignature(testSig)
) )
// makeTestDB creates a new instance of the ChannelDB for testing purposes. A // makeTestDB creates a new instance of the ChannelDB for testing purposes. A
@ -428,10 +430,10 @@ func TestChannelStateTransition(t *testing.T) {
Commitment: remoteCommit, Commitment: remoteCommit,
CommitSig: &lnwire.CommitSig{ CommitSig: &lnwire.CommitSig{
ChanID: lnwire.ChannelID(key), ChanID: lnwire.ChannelID(key),
CommitSig: testSig, CommitSig: wireSig,
HtlcSigs: []*btcec.Signature{ HtlcSigs: []lnwire.Sig{
testSig, wireSig,
testSig, wireSig,
}, },
}, },
LogUpdates: []LogUpdate{ LogUpdates: []LogUpdate{

@ -309,7 +309,8 @@ func (c *ChannelGraph) SourceNode() (*LightningNode, error) {
// node is to be used as the center of a star-graph within path finding // node is to be used as the center of a star-graph within path finding
// algorithms. // algorithms.
func (c *ChannelGraph) SetSourceNode(node *LightningNode) error { func (c *ChannelGraph) SetSourceNode(node *LightningNode) error {
nodePub := node.PubKey.SerializeCompressed() nodePubBytes := node.PubKeyBytes[:]
return c.db.Update(func(tx *bolt.Tx) error { return c.db.Update(func(tx *bolt.Tx) error {
// First grab the nodes bucket which stores the mapping from // First grab the nodes bucket which stores the mapping from
// pubKey to node information. // pubKey to node information.
@ -320,7 +321,7 @@ func (c *ChannelGraph) SetSourceNode(node *LightningNode) error {
// Next we create the mapping from source to the targeted // Next we create the mapping from source to the targeted
// public key. // public key.
if err := nodes.Put(sourceKey, nodePub); err != nil { if err := nodes.Put(sourceKey, nodePubBytes); err != nil {
return err return err
} }
@ -976,13 +977,13 @@ func (c *ChannelGraph) UpdateEdgePolicy(edge *ChannelEdgePolicy) error {
// from it. As the graph is directed, a node will also have an incoming edge // from it. As the graph is directed, a node will also have an incoming edge
// attached to it for each outgoing edge. // attached to it for each outgoing edge.
type LightningNode struct { type LightningNode struct {
// PubKey is the node's long-term identity public key. This key will be // PubKeyBytes is the raw bytes of the public key of the target node.
// used to authenticated any advertisements/updates sent by the node. PubKeyBytes [33]byte
PubKey *btcec.PublicKey pubKey *btcec.PublicKey
// HaveNodeAnnouncement indicates whether we received a node announcement // HaveNodeAnnouncement indicates whether we received a node
// for this particular node. If true, the remaining fields will be set, // announcement for this particular node. If true, the remaining fields
// if false only the PubKey is known for this node. // will be set, if false only the PubKey is known for this node.
HaveNodeAnnouncement bool HaveNodeAnnouncement bool
// LastUpdate is the last time the vertex information for this node has // LastUpdate is the last time the vertex information for this node has
@ -999,11 +1000,9 @@ type LightningNode struct {
// a node's identity or to serve as a short ID for an address book. // a node's identity or to serve as a short ID for an address book.
Alias string Alias string
// AuthSig is a signature under the advertised public key which serves // AuthSigBytes is the raw signature under the advertised public key
// to authenticate the attributes announced by this node. // which serves to authenticate the attributes announced by this node.
// AuthSigBytes []byte
// TODO(roasbeef): hook into serialization once full verification is in
AuthSig *btcec.Signature
// Features is the list of protocol features supported by this node. // Features is the list of protocol features supported by this node.
Features *lnwire.FeatureVector Features *lnwire.FeatureVector
@ -1016,6 +1015,42 @@ type LightningNode struct {
// TODO(roasbeef): add update method and fetch? // TODO(roasbeef): add update method and fetch?
} }
// PubKey is the node's long-term identity public key. This key will be used to
// authenticated any advertisements/updates sent by the node.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (l *LightningNode) PubKey() (*btcec.PublicKey, error) {
if l.pubKey != nil {
return l.pubKey, nil
}
key, err := btcec.ParsePubKey(l.PubKeyBytes[:], btcec.S256())
if err != nil {
return nil, err
}
l.pubKey = key
l.pubKey.Curve = nil
return key, nil
}
// AuthSig is a signature under the advertised public key which serves to
// authenticate the attributes announced by this node.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (l *LightningNode) AuthSig() (*btcec.Signature, error) {
return btcec.ParseSignature(l.AuthSigBytes, btcec.S256())
}
// AddPubKey is a setter-link method that can be used to swap out the public
// key for a node.
func (l *LightningNode) AddPubKey(key *btcec.PublicKey) {
l.pubKey = key
copy(l.PubKeyBytes[:], key.SerializeCompressed())
}
// FetchLightningNode attempts to look up a target node by its identity public // FetchLightningNode attempts to look up a target node by its identity public
// key. If the node isn't found in the database, then ErrGraphNodeNotFound is // key. If the node isn't found in the database, then ErrGraphNodeNotFound is
// returned. // returned.
@ -1062,13 +1097,12 @@ func (c *ChannelGraph) FetchLightningNode(pub *btcec.PublicKey) (*LightningNode,
// timestamp of when the data for the node was lasted updated is returned along // timestamp of when the data for the node was lasted updated is returned along
// with a true boolean. Otherwise, an empty time.Time is returned with a false // with a true boolean. Otherwise, an empty time.Time is returned with a false
// boolean. // boolean.
func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool, error) { func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, error) {
var ( var (
updateTime time.Time updateTime time.Time
exists bool exists bool
) )
nodePub := pub.SerializeCompressed()
err := c.db.View(func(tx *bolt.Tx) error { err := c.db.View(func(tx *bolt.Tx) error {
// First grab the nodes bucket which stores the mapping from // First grab the nodes bucket which stores the mapping from
// pubKey to node information. // pubKey to node information.
@ -1079,7 +1113,7 @@ func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool,
// If a key for this serialized public key isn't found, we can // If a key for this serialized public key isn't found, we can
// exit early. // exit early.
nodeBytes := nodes.Get(nodePub) nodeBytes := nodes.Get(nodePub[:])
if nodeBytes == nil { if nodeBytes == nil {
exists = false exists = false
return nil return nil
@ -1119,7 +1153,11 @@ func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool,
func (l *LightningNode) ForEachChannel(tx *bolt.Tx, func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
cb func(*bolt.Tx, *ChannelEdgeInfo, *ChannelEdgePolicy, *ChannelEdgePolicy) error) error { cb func(*bolt.Tx, *ChannelEdgeInfo, *ChannelEdgePolicy, *ChannelEdgePolicy) error) error {
nodePub := l.PubKey.SerializeCompressed() pub, err := l.PubKey()
if err != nil {
return err
}
nodePub := pub.SerializeCompressed()
traversal := func(tx *bolt.Tx) error { traversal := func(tx *bolt.Tx) error {
nodes := tx.Bucket(nodeBucket) nodes := tx.Bucket(nodeBucket)
@ -1172,7 +1210,12 @@ func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
// We'll also fetch the incoming edge so this // We'll also fetch the incoming edge so this
// information can be available to the caller. // information can be available to the caller.
incomingNode := toEdgePolicy.Node.PubKey.SerializeCompressed() incomingNodeKey, err := toEdgePolicy.Node.PubKey()
if err != nil {
return err
}
incomingNode := incomingNodeKey.SerializeCompressed()
fromEdgePolicy, err := fetchChanEdgePolicy( fromEdgePolicy, err := fetchChanEdgePolicy(
edges, chanID, incomingNode, nodes, edges, chanID, incomingNode, nodes,
) )
@ -1227,29 +1270,21 @@ type ChannelEdgeInfo struct {
// * must add chain hash to prefix as well // * must add chain hash to prefix as well
ChainHash chainhash.Hash ChainHash chainhash.Hash
// NodeKey1 is the identity public key of the "first" node that was // NodeKey1Bytes is the raw public key of the first node.
// involved in the creation of this channel. A node is considered NodeKey1Bytes [33]byte
// "first" if the lexicographical ordering the its serialized public nodeKey1 *btcec.PublicKey
// key is "smaller" than that of the other node involved in channel
// creation.
NodeKey1 *btcec.PublicKey
// NodeKey2 is the identity public key of the "second" node that was // NodeKey2Bytes is the raw public key of the first node.
// involved in the creation of this channel. A node is considered NodeKey2Bytes [33]byte
// "second" if the lexicographical ordering the its serialized public nodeKey2 *btcec.PublicKey
// key is "larger" than that of the other node involved in channel
// creation.
NodeKey2 *btcec.PublicKey
// BitcoinKey1 is the Bitcoin multi-sig key belonging to the first // BitcoinKey1Bytes is the raw public key of the first node.
// node, that was involved in the funding transaction that originally BitcoinKey1Bytes [33]byte
// created the channel that this struct represents. bitcoinKey1 *btcec.PublicKey
BitcoinKey1 *btcec.PublicKey
// BitcoinKey2 is the Bitcoin multi-sig key belonging to the second // BitcoinKey2Bytes is the raw public key of the first node.
// node, that was involved in the funding transaction that originally BitcoinKey2Bytes [33]byte
// created the channel that this struct represents. bitcoinKey2 *btcec.PublicKey
BitcoinKey2 *btcec.PublicKey
// Features is an opaque byte slice that encodes the set of channel // Features is an opaque byte slice that encodes the set of channel
// specific features that this channel edge supports. // specific features that this channel edge supports.
@ -1269,6 +1304,107 @@ type ChannelEdgeInfo struct {
Capacity btcutil.Amount Capacity btcutil.Amount
} }
// AddNodeKeys is a setter-like method that can be used to replace the set of
// keys for the target ChannelEdgeInfo.
func (c *ChannelEdgeInfo) AddNodeKeys(nodeKey1, nodeKey2, bitcoinKey1,
bitcoinKey2 *btcec.PublicKey) {
c.nodeKey1 = nodeKey1
copy(c.NodeKey1Bytes[:], c.nodeKey1.SerializeCompressed())
c.nodeKey2 = nodeKey2
copy(c.NodeKey2Bytes[:], nodeKey2.SerializeCompressed())
c.bitcoinKey1 = bitcoinKey1
copy(c.BitcoinKey1Bytes[:], c.bitcoinKey1.SerializeCompressed())
c.bitcoinKey2 = bitcoinKey2
copy(c.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
}
// NodeKey1 is the identity public key of the "first" node that was involved in
// the creation of this channel. A node is considered "first" if the
// lexicographical ordering the its serialized public key is "smaller" than
// that of the other node involved in channel creation.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (c *ChannelEdgeInfo) NodeKey1() (*btcec.PublicKey, error) {
if c.nodeKey1 != nil {
return c.nodeKey1, nil
}
key, err := btcec.ParsePubKey(c.NodeKey1Bytes[:], btcec.S256())
if err != nil {
return nil, err
}
c.nodeKey1 = key
return key, nil
}
// NodeKey2 is the identity public key of the "second" node that was
// involved in the creation of this channel. A node is considered
// "second" if the lexicographical ordering the its serialized public
// key is "larger" than that of the other node involved in channel
// creation.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (c *ChannelEdgeInfo) NodeKey2() (*btcec.PublicKey, error) {
if c.nodeKey2 != nil {
return c.nodeKey2, nil
}
key, err := btcec.ParsePubKey(c.NodeKey2Bytes[:], btcec.S256())
if err != nil {
return nil, err
}
c.nodeKey2 = key
return key, nil
}
// BitcoinKey1 is the Bitcoin multi-sig key belonging to the first
// node, that was involved in the funding transaction that originally
// created the channel that this struct represents.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (c *ChannelEdgeInfo) BitcoinKey1() (*btcec.PublicKey, error) {
if c.bitcoinKey1 != nil {
return c.bitcoinKey1, nil
}
key, err := btcec.ParsePubKey(c.BitcoinKey1Bytes[:], btcec.S256())
if err != nil {
return nil, err
}
c.bitcoinKey1 = key
return key, nil
}
// BitcoinKey2 is the Bitcoin multi-sig key belonging to the second
// node, that was involved in the funding transaction that originally
// created the channel that this struct represents.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (c *ChannelEdgeInfo) BitcoinKey2() (*btcec.PublicKey, error) {
if c.bitcoinKey2 != nil {
return c.bitcoinKey2, nil
}
key, err := btcec.ParsePubKey(c.BitcoinKey2Bytes[:], btcec.S256())
if err != nil {
return nil, err
}
c.bitcoinKey2 = key
return key, nil
}
// ChannelAuthProof is the authentication proof (the signature portion) for a // ChannelAuthProof is the authentication proof (the signature portion) for a
// channel. Using the four signatures contained in the struct, and some // channel. Using the four signatures contained in the struct, and some
// auxillary knowledge (the funding script, node identities, and outpoint) nodes // auxillary knowledge (the funding script, node identities, and outpoint) nodes
@ -1277,32 +1413,124 @@ type ChannelEdgeInfo struct {
// nodeID1 || nodeID2 || bitcoinKey1|| bitcoinKey2 || 2-byte-feature-len || // nodeID1 || nodeID2 || bitcoinKey1|| bitcoinKey2 || 2-byte-feature-len ||
// features. // features.
type ChannelAuthProof struct { type ChannelAuthProof struct {
// NodeSig1 is the signature using the identity key of the node that is // nodeSig1 is a cached instance of the first node signature.
// first in a lexicographical ordering of the serialized public keys of nodeSig1 *btcec.Signature
// the two nodes that created the channel.
NodeSig1 *btcec.Signature
// NodeSig2 is the signature using the identity key of the node that is // NodeSig1Bytes are the raw bytes of the first node signature encoded
// second in a lexicographical ordering of the serialized public keys // in DER format.
// of the two nodes that created the channel. NodeSig1Bytes []byte
NodeSig2 *btcec.Signature
// BitcoinSig1 is the signature using the public key of the first node // nodeSig2 is a cached instance of the second node signature.
// that was used in the channel's multi-sig output. nodeSig2 *btcec.Signature
BitcoinSig1 *btcec.Signature
// BitcoinSig2 is the signature using the public key of the second node // NodeSig2Bytes are the raw bytes of the second node signature
// that was used in the channel's multi-sig output. // encoded in DER format.
BitcoinSig2 *btcec.Signature NodeSig2Bytes []byte
// bitcoinSig1 is a cached instance of the first bitcoin signature.
bitcoinSig1 *btcec.Signature
// BitcoinSig1Bytes are the raw bytes of the first bitcoin signature
// encoded in DER format.
BitcoinSig1Bytes []byte
// bitcoinSig2 is a cached instance of the second bitcoin signature.
bitcoinSig2 *btcec.Signature
// BitcoinSig2Bytes are the raw bytes of the second bitcoin signature
// encoded in DER format.
BitcoinSig2Bytes []byte
}
// Node1Sig is the signature using the identity key of the node that is first
// in a lexicographical ordering of the serialized public keys of the two nodes
// that created the channel.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (c *ChannelAuthProof) Node1Sig() (*btcec.Signature, error) {
if c.nodeSig1 != nil {
return c.nodeSig1, nil
}
sig, err := btcec.ParseSignature(c.NodeSig1Bytes, btcec.S256())
if err != nil {
return nil, err
}
c.nodeSig1 = sig
return sig, nil
}
// Node2Sig is the signature using the identity key of the node that is second
// in a lexicographical ordering of the serialized public keys of the two nodes
// that created the channel.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (c *ChannelAuthProof) Node2Sig() (*btcec.Signature, error) {
if c.nodeSig2 != nil {
return c.nodeSig2, nil
}
sig, err := btcec.ParseSignature(c.NodeSig2Bytes, btcec.S256())
if err != nil {
return nil, err
}
c.nodeSig2 = sig
return sig, nil
}
// BitcoinSig1 is the signature using the public key of the first node that was
// used in the channel's multi-sig output.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (c *ChannelAuthProof) BitcoinSig1() (*btcec.Signature, error) {
if c.bitcoinSig1 != nil {
return c.bitcoinSig1, nil
}
sig, err := btcec.ParseSignature(c.BitcoinSig1Bytes, btcec.S256())
if err != nil {
return nil, err
}
c.bitcoinSig1 = sig
return sig, nil
}
// BitcoinSig2 is the signature using the public key of the second node that
// was used in the channel's multi-sig output.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (c *ChannelAuthProof) BitcoinSig2() (*btcec.Signature, error) {
if c.bitcoinSig2 != nil {
return c.bitcoinSig2, nil
}
sig, err := btcec.ParseSignature(c.BitcoinSig2Bytes, btcec.S256())
if err != nil {
return nil, err
}
c.bitcoinSig2 = sig
return sig, nil
} }
// IsEmpty check is the authentication proof is empty Proof is empty if at // IsEmpty check is the authentication proof is empty Proof is empty if at
// least one of the signatures are equal to nil. // least one of the signatures are equal to nil.
func (p *ChannelAuthProof) IsEmpty() bool { func (c *ChannelAuthProof) IsEmpty() bool {
return p.NodeSig1 == nil || return len(c.NodeSig1Bytes) == 0 ||
p.NodeSig2 == nil || len(c.NodeSig2Bytes) == 0 ||
p.BitcoinSig1 == nil || len(c.BitcoinSig1Bytes) == 0 ||
p.BitcoinSig2 == nil len(c.BitcoinSig2Bytes) == 0
} }
// ChannelEdgePolicy represents a *directed* edge within the channel graph. For // ChannelEdgePolicy represents a *directed* edge within the channel graph. For
@ -1311,9 +1539,13 @@ func (p *ChannelAuthProof) IsEmpty() bool {
// information concerning fees, and minimum time-lock information which is // information concerning fees, and minimum time-lock information which is
// utilized during path finding. // utilized during path finding.
type ChannelEdgePolicy struct { type ChannelEdgePolicy struct {
// Signature is a channel announcement signature, which is needed for // SigBytes is the raw bytes of the signature of the channel edge
// proper edge policy announcement. // policy. We'll only parse these if the caller needs to access the
Signature *btcec.Signature // signature for validation purposes.
SigBytes []byte
// sig is a cached fully parsed signature.
sig *btcec.Signature
// ChannelID is the unique channel ID for the channel. The first 3 // ChannelID is the unique channel ID for the channel. The first 3
// bytes are the block height, the next 3 the index within the block, // bytes are the block height, the next 3 the index within the block,
@ -1352,6 +1584,26 @@ type ChannelEdgePolicy struct {
db *DB db *DB
} }
// Signature is a channel announcement signature, which is needed for proper
// edge policy announcement.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the signature if absolutely necessary.
func (c *ChannelEdgePolicy) Signature() (*btcec.Signature, error) {
if c.sig != nil {
return c.sig, nil
}
sig, err := btcec.ParseSignature(c.SigBytes, btcec.S256())
if err != nil {
return nil, err
}
c.sig = sig
return sig, nil
}
// FetchChannelEdgesByOutpoint attempts to lookup the two directed edges for // FetchChannelEdgesByOutpoint attempts to lookup the two directed edges for
// the channel identified by the funding outpoint. If the channel can't be // the channel identified by the funding outpoint. If the channel can't be
// found, then ErrEdgeNotFound is returned. A struct which houses the general // found, then ErrEdgeNotFound is returned. A struct which houses the general
@ -1539,7 +1791,11 @@ func putLightningNode(nodeBucket *bolt.Bucket, aliasBucket *bolt.Bucket, node *L
b bytes.Buffer b bytes.Buffer
) )
nodePub := node.PubKey.SerializeCompressed() pub, err := node.PubKey()
if err != nil {
return err
}
nodePub := pub.SerializeCompressed()
// If the node has the update time set, write it, else write 0. // If the node has the update time set, write it, else write 0.
updateUnix := uint64(0) updateUnix := uint64(0)
@ -1604,7 +1860,7 @@ func putLightningNode(nodeBucket *bolt.Bucket, aliasBucket *bolt.Bucket, node *L
} }
} }
err := wire.WriteVarBytes(&b, 0, node.AuthSig.Serialize()) err = wire.WriteVarBytes(&b, 0, node.AuthSigBytes)
if err != nil { if err != nil {
return err return err
} }
@ -1630,8 +1886,12 @@ func fetchLightningNode(nodeBucket *bolt.Bucket,
} }
func deserializeLightningNode(r io.Reader) (*LightningNode, error) { func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
var (
scratch [8]byte
err error
)
node := &LightningNode{} node := &LightningNode{}
var scratch [8]byte
if _, err := r.Read(scratch[:]); err != nil { if _, err := r.Read(scratch[:]); err != nil {
return nil, err return nil, err
@ -1640,13 +1900,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
unix := int64(byteOrder.Uint64(scratch[:])) unix := int64(byteOrder.Uint64(scratch[:]))
node.LastUpdate = time.Unix(unix, 0) node.LastUpdate = time.Unix(unix, 0)
var pub [33]byte if _, err := io.ReadFull(r, node.PubKeyBytes[:]); err != nil {
if _, err := r.Read(pub[:]); err != nil {
return nil, err
}
var err error
node.PubKey, err = btcec.ParsePubKey(pub[:], btcec.S256())
if err != nil {
return nil, err return nil, err
} }
@ -1706,12 +1960,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
} }
node.Addresses = addresses node.Addresses = addresses
sigBytes, err := wire.ReadVarBytes(r, 0, 80, "sig") node.AuthSigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
if err != nil {
return nil, err
}
node.AuthSig, err = btcec.ParseSignature(sigBytes, btcec.S256())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1722,16 +1971,16 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [8]byte) error { func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [8]byte) error {
var b bytes.Buffer var b bytes.Buffer
if _, err := b.Write(edgeInfo.NodeKey1.SerializeCompressed()); err != nil { if _, err := b.Write(edgeInfo.NodeKey1Bytes[:]); err != nil {
return err return err
} }
if _, err := b.Write(edgeInfo.NodeKey2.SerializeCompressed()); err != nil { if _, err := b.Write(edgeInfo.NodeKey2Bytes[:]); err != nil {
return err return err
} }
if _, err := b.Write(edgeInfo.BitcoinKey1.SerializeCompressed()); err != nil { if _, err := b.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil {
return err return err
} }
if _, err := b.Write(edgeInfo.BitcoinKey2.SerializeCompressed()); err != nil { if _, err := b.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil {
return err return err
} }
@ -1742,10 +1991,10 @@ func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [
authProof := edgeInfo.AuthProof authProof := edgeInfo.AuthProof
var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte
if authProof != nil { if authProof != nil {
nodeSig1 = authProof.NodeSig1.Serialize() nodeSig1 = authProof.NodeSig1Bytes
nodeSig2 = authProof.NodeSig2.Serialize() nodeSig2 = authProof.NodeSig2Bytes
bitcoinSig1 = authProof.BitcoinSig1.Serialize() bitcoinSig1 = authProof.BitcoinSig1Bytes
bitcoinSig2 = authProof.BitcoinSig2.Serialize() bitcoinSig2 = authProof.BitcoinSig2Bytes
} }
if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil { if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil {
@ -1791,33 +2040,20 @@ func fetchChanEdgeInfo(edgeIndex *bolt.Bucket,
func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) { func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) {
var ( var (
err error err error
pubKeyBytes [33]byte edgeInfo = &ChannelEdgeInfo{}
edgeInfo = &ChannelEdgeInfo{}
) )
readKey := func() (*btcec.PublicKey, error) { if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil {
if _, err := io.ReadFull(r, pubKeyBytes[:]); err != nil {
return nil, err
}
return btcec.ParsePubKey(pubKeyBytes[:], btcec.S256())
}
edgeInfo.NodeKey1, err = readKey()
if err != nil {
return nil, err return nil, err
} }
edgeInfo.NodeKey2, err = readKey() if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil {
if err != nil {
return nil, err return nil, err
} }
edgeInfo.BitcoinKey1, err = readKey() if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil {
if err != nil {
return nil, err return nil, err
} }
edgeInfo.BitcoinKey2, err = readKey() if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil {
if err != nil {
return nil, err return nil, err
} }
@ -1828,32 +2064,23 @@ func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) {
proof := &ChannelAuthProof{} proof := &ChannelAuthProof{}
readSig := func() (*btcec.Signature, error) { readSig := func() ([]byte, error) {
sigBytes, err := wire.ReadVarBytes(r, 0, 80, "sigs") return wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
}
if len(sigBytes) != 0 {
return btcec.ParseSignature(sigBytes, btcec.S256())
}
return nil, nil
} }
proof.NodeSig1, err = readSig() proof.NodeSig1Bytes, err = readSig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
proof.NodeSig2, err = readSig() proof.NodeSig2Bytes, err = readSig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
proof.BitcoinSig1, err = readSig() proof.BitcoinSig1Bytes, err = readSig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
proof.BitcoinSig2, err = readSig() proof.BitcoinSig2Bytes, err = readSig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1887,7 +2114,7 @@ func putChanEdgePolicy(edges *bolt.Bucket, edge *ChannelEdgePolicy, from, to []b
var b bytes.Buffer var b bytes.Buffer
err := wire.WriteVarBytes(&b, 0, edge.Signature.Serialize()) err := wire.WriteVarBytes(&b, 0, edge.SigBytes)
if err != nil { if err != nil {
return err return err
} }
@ -1993,11 +2220,7 @@ func deserializeChanEdgePolicy(r io.Reader,
if err != nil { if err != nil {
return nil, err return nil, err
} }
edge.SigBytes = sigBytes
edge.Signature, err = btcec.ParseSignature(sigBytes, btcec.S256())
if err != nil {
return nil, err
}
if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil { if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil {
return nil, err return nil, err

@ -50,17 +50,19 @@ func createTestVertex(db *DB) (*LightningNode, error) {
} }
pub := priv.PubKey().SerializeCompressed() pub := priv.PubKey().SerializeCompressed()
return &LightningNode{ n := &LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(updateTime, 0), LastUpdate: time.Unix(updateTime, 0),
PubKey: priv.PubKey(),
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + string(pub[:]), Alias: "kek" + string(pub[:]),
Features: testFeatures, Features: testFeatures,
Addresses: testAddrs, Addresses: testAddrs,
db: db, db: db,
}, nil }
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
return n, nil
} }
func TestNodeInsertionAndDeletion(t *testing.T) { func TestNodeInsertionAndDeletion(t *testing.T) {
@ -79,15 +81,15 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
_, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:]) _, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:])
node := &LightningNode{ node := &LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(1232342, 0), LastUpdate: time.Unix(1232342, 0),
PubKey: testPub,
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "kek", Alias: "kek",
Features: testFeatures, Features: testFeatures,
Addresses: testAddrs, Addresses: testAddrs,
db: db, db: db,
} }
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
// First, insert the node into the graph DB. This should succeed // First, insert the node into the graph DB. This should succeed
// without any errors. // without any errors.
@ -102,7 +104,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
t.Fatalf("unable to locate node: %v", err) t.Fatalf("unable to locate node: %v", err)
} }
if _, exists, err := graph.HasLightningNode(testPub); err != nil { if _, exists, err := graph.HasLightningNode(dbNode.PubKeyBytes); err != nil {
t.Fatalf("unable to query for node: %v", err) t.Fatalf("unable to query for node: %v", err)
} else if !exists { } else if !exists {
t.Fatalf("node should be found but wasn't") t.Fatalf("node should be found but wasn't")
@ -144,9 +146,9 @@ func TestPartialNode(t *testing.T) {
// PubKey set. // PubKey set.
_, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:]) _, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:])
node := &LightningNode{ node := &LightningNode{
PubKey: testPub,
HaveNodeAnnouncement: false, HaveNodeAnnouncement: false,
} }
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
if err := graph.AddLightningNode(node); err != nil { if err := graph.AddLightningNode(node); err != nil {
t.Fatalf("unable to add node: %v", err) t.Fatalf("unable to add node: %v", err)
@ -159,7 +161,7 @@ func TestPartialNode(t *testing.T) {
t.Fatalf("unable to locate node: %v", err) t.Fatalf("unable to locate node: %v", err)
} }
if _, exists, err := graph.HasLightningNode(testPub); err != nil { if _, exists, err := graph.HasLightningNode(dbNode.PubKeyBytes); err != nil {
t.Fatalf("unable to query for node: %v", err) t.Fatalf("unable to query for node: %v", err)
} else if !exists { } else if !exists {
t.Fatalf("node should be found but wasn't") t.Fatalf("node should be found but wasn't")
@ -168,11 +170,11 @@ func TestPartialNode(t *testing.T) {
// The two nodes should match exactly! (with default values for // The two nodes should match exactly! (with default values for
// LastUpdate and db set to satisfy compareNodes()) // LastUpdate and db set to satisfy compareNodes())
node = &LightningNode{ node = &LightningNode{
PubKey: testPub,
HaveNodeAnnouncement: false, HaveNodeAnnouncement: false,
LastUpdate: time.Unix(0, 0), LastUpdate: time.Unix(0, 0),
db: db, db: db,
} }
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
if err := compareNodes(node, dbNode); err != nil { if err := compareNodes(node, dbNode); err != nil {
t.Fatalf("nodes don't match: %v", err) t.Fatalf("nodes don't match: %v", err)
@ -181,7 +183,7 @@ func TestPartialNode(t *testing.T) {
// Next, delete the node from the graph, this should purge all data // Next, delete the node from the graph, this should purge all data
// related to the node. // related to the node.
if err := graph.DeleteLightningNode(testPub); err != nil { if err := graph.DeleteLightningNode(testPub); err != nil {
t.Fatalf("unable to delete node; %v", err) t.Fatalf("unable to delete node: %v", err)
} }
// Finally, attempt to fetch the node again. This should fail as the // Finally, attempt to fetch the node again. This should fail as the
@ -218,7 +220,11 @@ func TestAliasLookup(t *testing.T) {
// Next, attempt to lookup the alias. The alias should exactly match // Next, attempt to lookup the alias. The alias should exactly match
// the one which the test node was assigned. // the one which the test node was assigned.
dbAlias, err := graph.LookupAlias(testNode.PubKey) nodePub, err := testNode.PubKey()
if err != nil {
t.Fatalf("unable to generate pubkey: %v", err)
}
dbAlias, err := graph.LookupAlias(nodePub)
if err != nil { if err != nil {
t.Fatalf("unable to find alias: %v", err) t.Fatalf("unable to find alias: %v", err)
} }
@ -232,7 +238,11 @@ func TestAliasLookup(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to create test node: %v", err) t.Fatalf("unable to create test node: %v", err)
} }
_, err = graph.LookupAlias(node.PubKey) nodePub, err = node.PubKey()
if err != nil {
t.Fatalf("unable to generate pubkey: %v", err)
}
_, err = graph.LookupAlias(nodePub)
if err != ErrNodeAliasNotFound { if err != ErrNodeAliasNotFound {
t.Fatalf("alias lookup should fail for non-existent pubkey") t.Fatalf("alias lookup should fail for non-existent pubkey")
} }
@ -311,22 +321,30 @@ func TestEdgeInsertionDeletion(t *testing.T) {
// Add the new edge to the database, this should proceed without any // Add the new edge to the database, this should proceed without any
// errors. // errors.
node1Pub, err := node1.PubKey()
if err != nil {
t.Fatalf("unable to generate node key: %v", err)
}
node2Pub, err := node2.PubKey()
if err != nil {
t.Fatalf("unable to generate node key: %v", err)
}
edgeInfo := ChannelEdgeInfo{ edgeInfo := ChannelEdgeInfo{
ChannelID: chanID, ChannelID: chanID,
ChainHash: key, ChainHash: key,
NodeKey1: node1.PubKey,
NodeKey2: node2.PubKey,
BitcoinKey1: node1.PubKey,
BitcoinKey2: node2.PubKey,
AuthProof: &ChannelAuthProof{ AuthProof: &ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
ChannelPoint: outpoint, ChannelPoint: outpoint,
Capacity: 9000, Capacity: 9000,
} }
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.NodeKey2Bytes[:], node2Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey2Bytes[:], node2Pub.SerializeCompressed())
if err := graph.AddChannelEdge(&edgeInfo); err != nil { if err := graph.AddChannelEdge(&edgeInfo); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
@ -413,22 +431,26 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
Index: outPointIndex, Index: outPointIndex,
} }
node1Pub, _ := node1.PubKey()
node2Pub, _ := node2.PubKey()
edgeInfo := ChannelEdgeInfo{ edgeInfo := ChannelEdgeInfo{
ChannelID: shortChanID.ToUint64(), ChannelID: shortChanID.ToUint64(),
ChainHash: key, ChainHash: key,
NodeKey1: node1.PubKey,
NodeKey2: node2.PubKey,
BitcoinKey1: node1.PubKey,
BitcoinKey2: node2.PubKey,
AuthProof: &ChannelAuthProof{ AuthProof: &ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
ChannelPoint: outpoint, ChannelPoint: outpoint,
Capacity: 9000, Capacity: 9000,
} }
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.NodeKey2Bytes[:], node2Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey2Bytes[:], node2Pub.SerializeCompressed())
return edgeInfo return edgeInfo
} }
@ -530,16 +552,16 @@ func assertEdgeInfoEqual(t *testing.T, e1 *ChannelEdgeInfo,
e2.ChainHash) e2.ChainHash)
} }
if !e1.NodeKey1.IsEqual(e2.NodeKey1) { if !bytes.Equal(e1.NodeKey1Bytes[:], e2.NodeKey1Bytes[:]) {
t.Fatalf("nodekey1 doesn't match") t.Fatalf("nodekey1 doesn't match")
} }
if !e1.NodeKey2.IsEqual(e2.NodeKey2) { if !bytes.Equal(e1.NodeKey2Bytes[:], e2.NodeKey2Bytes[:]) {
t.Fatalf("nodekey2 doesn't match") t.Fatalf("nodekey2 doesn't match")
} }
if !e1.BitcoinKey1.IsEqual(e2.BitcoinKey1) { if !bytes.Equal(e1.BitcoinKey1Bytes[:], e2.BitcoinKey1Bytes[:]) {
t.Fatalf("bitcoinkey1 doesn't match") t.Fatalf("bitcoinkey1 doesn't match")
} }
if !e1.BitcoinKey2.IsEqual(e2.BitcoinKey2) { if !bytes.Equal(e1.BitcoinKey2Bytes[:], e2.BitcoinKey2Bytes[:]) {
t.Fatalf("bitcoinkey2 doesn't match") t.Fatalf("bitcoinkey2 doesn't match")
} }
@ -548,18 +570,18 @@ func assertEdgeInfoEqual(t *testing.T, e1 *ChannelEdgeInfo,
e2.Features) e2.Features)
} }
if !e1.AuthProof.NodeSig1.IsEqual(e2.AuthProof.NodeSig1) { if !bytes.Equal(e1.AuthProof.NodeSig1Bytes, e2.AuthProof.NodeSig1Bytes) {
t.Fatalf("nodesig1 doesn't match: %v vs %v", t.Fatalf("nodesig1 doesn't match: %v vs %v",
spew.Sdump(e1.AuthProof.NodeSig1), spew.Sdump(e1.AuthProof.NodeSig1Bytes),
spew.Sdump(e2.AuthProof.NodeSig1)) spew.Sdump(e2.AuthProof.NodeSig1Bytes))
} }
if !e1.AuthProof.NodeSig2.IsEqual(e2.AuthProof.NodeSig2) { if !bytes.Equal(e1.AuthProof.NodeSig2Bytes, e2.AuthProof.NodeSig2Bytes) {
t.Fatalf("nodesig2 doesn't match") t.Fatalf("nodesig2 doesn't match")
} }
if !e1.AuthProof.BitcoinSig1.IsEqual(e2.AuthProof.BitcoinSig1) { if !bytes.Equal(e1.AuthProof.BitcoinSig1Bytes, e2.AuthProof.BitcoinSig1Bytes) {
t.Fatalf("bitcoinsig1 doesn't match") t.Fatalf("bitcoinsig1 doesn't match")
} }
if !e1.AuthProof.BitcoinSig2.IsEqual(e2.AuthProof.BitcoinSig2) { if !bytes.Equal(e1.AuthProof.BitcoinSig2Bytes, e2.AuthProof.BitcoinSig2Bytes) {
t.Fatalf("bitcoinsig2 doesn't match") t.Fatalf("bitcoinsig2 doesn't match")
} }
@ -606,9 +628,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
firstNode *LightningNode firstNode *LightningNode
secondNode *LightningNode secondNode *LightningNode
) )
node1Bytes := node1.PubKey.SerializeCompressed() if bytes.Compare(node1.PubKeyBytes[:], node2.PubKeyBytes[:]) == -1 {
node2Bytes := node2.PubKey.SerializeCompressed()
if bytes.Compare(node1Bytes, node2Bytes) == -1 {
firstNode = node1 firstNode = node1
secondNode = node2 secondNode = node2
} else { } else {
@ -627,21 +647,21 @@ func TestEdgeInfoUpdates(t *testing.T) {
// Add the new edge to the database, this should proceed without any // Add the new edge to the database, this should proceed without any
// errors. // errors.
edgeInfo := &ChannelEdgeInfo{ edgeInfo := &ChannelEdgeInfo{
ChannelID: chanID, ChannelID: chanID,
ChainHash: key, ChainHash: key,
NodeKey1: firstNode.PubKey,
NodeKey2: secondNode.PubKey,
BitcoinKey1: firstNode.PubKey,
BitcoinKey2: secondNode.PubKey,
AuthProof: &ChannelAuthProof{ AuthProof: &ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
ChannelPoint: outpoint, ChannelPoint: outpoint,
Capacity: 1000, Capacity: 1000,
} }
copy(edgeInfo.NodeKey1Bytes[:], firstNode.PubKeyBytes[:])
copy(edgeInfo.NodeKey2Bytes[:], secondNode.PubKeyBytes[:])
copy(edgeInfo.BitcoinKey1Bytes[:], firstNode.PubKeyBytes[:])
copy(edgeInfo.BitcoinKey2Bytes[:], secondNode.PubKeyBytes[:])
if err := graph.AddChannelEdge(edgeInfo); err != nil { if err := graph.AddChannelEdge(edgeInfo); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@ -649,7 +669,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
// With the edge added, we can now create some fake edge information to // With the edge added, we can now create some fake edge information to
// update for both edges. // update for both edges.
edge1 := &ChannelEdgePolicy{ edge1 := &ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: chanID, ChannelID: chanID,
LastUpdate: time.Unix(433453, 0), LastUpdate: time.Unix(433453, 0),
Flags: 0, Flags: 0,
@ -661,7 +681,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
db: db, db: db,
} }
edge2 := &ChannelEdgePolicy{ edge2 := &ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: chanID, ChannelID: chanID,
LastUpdate: time.Unix(124234, 0), LastUpdate: time.Unix(124234, 0),
Flags: 1, Flags: 1,
@ -796,9 +816,7 @@ func TestGraphTraversal(t *testing.T) {
// Determine which node is "smaller", we'll need this in order to // Determine which node is "smaller", we'll need this in order to
// properly create the edges for the graph. // properly create the edges for the graph.
var firstNode, secondNode *LightningNode var firstNode, secondNode *LightningNode
node1Bytes := nodes[0].PubKey.SerializeCompressed() if bytes.Compare(nodes[0].PubKeyBytes[:], nodes[1].PubKeyBytes[:]) == -1 {
node2Bytes := nodes[1].PubKey.SerializeCompressed()
if bytes.Compare(node1Bytes, node2Bytes) == -1 {
firstNode = nodes[0] firstNode = nodes[0]
secondNode = nodes[1] secondNode = nodes[1]
} else { } else {
@ -818,21 +836,21 @@ func TestGraphTraversal(t *testing.T) {
} }
edgeInfo := ChannelEdgeInfo{ edgeInfo := ChannelEdgeInfo{
ChannelID: chanID, ChannelID: chanID,
ChainHash: key, ChainHash: key,
NodeKey1: nodes[0].PubKey,
NodeKey2: nodes[1].PubKey,
BitcoinKey1: nodes[0].PubKey,
BitcoinKey2: nodes[1].PubKey,
AuthProof: &ChannelAuthProof{ AuthProof: &ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
ChannelPoint: op, ChannelPoint: op,
Capacity: 1000, Capacity: 1000,
} }
copy(edgeInfo.NodeKey1Bytes[:], nodes[0].PubKeyBytes[:])
copy(edgeInfo.NodeKey2Bytes[:], nodes[1].PubKeyBytes[:])
copy(edgeInfo.BitcoinKey1Bytes[:], nodes[0].PubKeyBytes[:])
copy(edgeInfo.BitcoinKey2Bytes[:], nodes[1].PubKeyBytes[:])
err := graph.AddChannelEdge(&edgeInfo) err := graph.AddChannelEdge(&edgeInfo)
if err != nil { if err != nil {
t.Fatalf("unable to add node: %v", err) t.Fatalf("unable to add node: %v", err)
@ -843,7 +861,7 @@ func TestGraphTraversal(t *testing.T) {
edge := randEdgePolicy(chanID, op, db) edge := randEdgePolicy(chanID, op, db)
edge.Flags = 0 edge.Flags = 0
edge.Node = secondNode edge.Node = secondNode
edge.Signature = testSig edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil { if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err) t.Fatalf("unable to update edge: %v", err)
} }
@ -853,7 +871,7 @@ func TestGraphTraversal(t *testing.T) {
edge = randEdgePolicy(chanID, op, db) edge = randEdgePolicy(chanID, op, db)
edge.Flags = 1 edge.Flags = 1
edge.Node = firstNode edge.Node = firstNode
edge.Signature = testSig edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil { if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err) t.Fatalf("unable to update edge: %v", err)
} }
@ -885,13 +903,13 @@ func TestGraphTraversal(t *testing.T) {
// Each each should indicate that it's outgoing (pointed // Each each should indicate that it's outgoing (pointed
// towards the second node). // towards the second node).
if !outEdge.Node.PubKey.IsEqual(secondNode.PubKey) { if !bytes.Equal(outEdge.Node.PubKeyBytes[:], secondNode.PubKeyBytes[:]) {
return fmt.Errorf("wrong outgoing edge") return fmt.Errorf("wrong outgoing edge")
} }
// The incoming edge should also indicate that it's pointing to // The incoming edge should also indicate that it's pointing to
// the origin node. // the origin node.
if !inEdge.Node.PubKey.IsEqual(firstNode.PubKey) { if !bytes.Equal(inEdge.Node.PubKeyBytes[:], firstNode.PubKeyBytes[:]) {
return fmt.Errorf("wrong outgoing edge") return fmt.Errorf("wrong outgoing edge")
} }
@ -1008,22 +1026,21 @@ func TestGraphPruning(t *testing.T) {
channelPoints = append(channelPoints, &op) channelPoints = append(channelPoints, &op)
edgeInfo := ChannelEdgeInfo{ edgeInfo := ChannelEdgeInfo{
ChannelID: chanID, ChannelID: chanID,
ChainHash: key, ChainHash: key,
NodeKey1: graphNodes[i].PubKey,
NodeKey2: graphNodes[i+1].PubKey,
BitcoinKey1: graphNodes[i].PubKey,
BitcoinKey2: graphNodes[i+1].PubKey,
AuthProof: &ChannelAuthProof{ AuthProof: &ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
ChannelPoint: op, ChannelPoint: op,
Capacity: 1000, Capacity: 1000,
} }
copy(edgeInfo.NodeKey1Bytes[:], graphNodes[i].PubKeyBytes[:])
copy(edgeInfo.NodeKey2Bytes[:], graphNodes[i+1].PubKeyBytes[:])
copy(edgeInfo.BitcoinKey1Bytes[:], graphNodes[i].PubKeyBytes[:])
copy(edgeInfo.BitcoinKey2Bytes[:], graphNodes[i+1].PubKeyBytes[:])
if err := graph.AddChannelEdge(&edgeInfo); err != nil { if err := graph.AddChannelEdge(&edgeInfo); err != nil {
t.Fatalf("unable to add node: %v", err) t.Fatalf("unable to add node: %v", err)
} }
@ -1033,7 +1050,7 @@ func TestGraphPruning(t *testing.T) {
edge := randEdgePolicy(chanID, op, db) edge := randEdgePolicy(chanID, op, db)
edge.Flags = 0 edge.Flags = 0
edge.Node = graphNodes[i] edge.Node = graphNodes[i]
edge.Signature = testSig edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil { if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err) t.Fatalf("unable to update edge: %v", err)
} }
@ -1043,7 +1060,7 @@ func TestGraphPruning(t *testing.T) {
edge = randEdgePolicy(chanID, op, db) edge = randEdgePolicy(chanID, op, db)
edge.Flags = 1 edge.Flags = 1
edge.Node = graphNodes[i] edge.Node = graphNodes[i]
edge.Signature = testSig edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil { if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err) t.Fatalf("unable to update edge: %v", err)
} }
@ -1159,9 +1176,9 @@ func compareNodes(a, b *LightningNode) error {
return fmt.Errorf("Addresses doesn't match: expected %#v, \n "+ return fmt.Errorf("Addresses doesn't match: expected %#v, \n "+
"got %#v", a.Addresses, b.Addresses) "got %#v", a.Addresses, b.Addresses)
} }
if !reflect.DeepEqual(a.PubKey, b.PubKey) { if !reflect.DeepEqual(a.PubKeyBytes, b.PubKeyBytes) {
return fmt.Errorf("PubKey doesn't match: expected %#v, \n "+ return fmt.Errorf("PubKey doesn't match: expected %#v, \n "+
"got %#v", a.PubKey, b.PubKey) "got %#v", a.PubKeyBytes, b.PubKeyBytes)
} }
if !reflect.DeepEqual(a.Color, b.Color) { if !reflect.DeepEqual(a.Color, b.Color) {
return fmt.Errorf("Color doesn't match: expected %#v, \n "+ return fmt.Errorf("Color doesn't match: expected %#v, \n "+

@ -21,8 +21,8 @@ func TestWaitingProofStore(t *testing.T) {
defer cleanup() defer cleanup()
proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures{ proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures{
NodeSignature: testSig, NodeSignature: wireSig,
BitcoinSignature: testSig, BitcoinSignature: wireSig,
}) })
store, err := NewWaitingProofStore(db) store, err := NewWaitingProofStore(db)

@ -26,23 +26,56 @@ func ValidateChannelAnn(a *lnwire.ChannelAnnouncement) error {
// First we'll verify that the passed bitcoin key signature is indeed a // First we'll verify that the passed bitcoin key signature is indeed a
// signature over the computed hash digest. // signature over the computed hash digest.
if !a.BitcoinSig1.Verify(dataHash, copyPubKey(a.BitcoinKey1)) { bitcoinSig1, err := a.BitcoinSig1.ToSignature()
if err != nil {
return err
}
bitcoinKey1, err := btcec.ParsePubKey(a.BitcoinKey1[:], btcec.S256())
if err != nil {
return err
}
if !bitcoinSig1.Verify(dataHash, bitcoinKey1) {
return errors.New("can't verify first bitcoin signature") return errors.New("can't verify first bitcoin signature")
} }
// If that checks out, then we'll verify that the second bitcoin // If that checks out, then we'll verify that the second bitcoin
// signature is a valid signature of the bitcoin public key over hash // signature is a valid signature of the bitcoin public key over hash
// digest as well. // digest as well.
if !a.BitcoinSig2.Verify(dataHash, copyPubKey(a.BitcoinKey2)) { bitcoinSig2, err := a.BitcoinSig2.ToSignature()
if err != nil {
return err
}
bitcoinKey2, err := btcec.ParsePubKey(a.BitcoinKey2[:], btcec.S256())
if err != nil {
return err
}
if !bitcoinSig2.Verify(dataHash, bitcoinKey2) {
return errors.New("can't verify second bitcoin signature") return errors.New("can't verify second bitcoin signature")
} }
// Both node signatures attached should indeed be a valid signature // Both node signatures attached should indeed be a valid signature
// over the selected digest of the channel announcement signature. // over the selected digest of the channel announcement signature.
if !a.NodeSig1.Verify(dataHash, copyPubKey(a.NodeID1)) { nodeSig1, err := a.NodeSig1.ToSignature()
if err != nil {
return err
}
nodeKey1, err := btcec.ParsePubKey(a.NodeID1[:], btcec.S256())
if err != nil {
return err
}
if !nodeSig1.Verify(dataHash, nodeKey1) {
return errors.New("can't verify data in first node signature") return errors.New("can't verify data in first node signature")
} }
if !a.NodeSig2.Verify(dataHash, copyPubKey(a.NodeID2)) {
nodeSig2, err := a.NodeSig2.ToSignature()
if err != nil {
return err
}
nodeKey2, err := btcec.ParsePubKey(a.NodeID2[:], btcec.S256())
if err != nil {
return err
}
if !nodeSig2.Verify(dataHash, nodeKey2) {
return errors.New("can't verify data in second node signature") return errors.New("can't verify data in second node signature")
} }
@ -61,17 +94,26 @@ func ValidateNodeAnn(a *lnwire.NodeAnnouncement) error {
return err return err
} }
nodeSig, err := a.Signature.ToSignature()
if err != nil {
return err
}
nodeKey, err := btcec.ParsePubKey(a.NodeID[:], btcec.S256())
if err != nil {
return err
}
// Finally ensure that the passed signature is valid, if not we'll // Finally ensure that the passed signature is valid, if not we'll
// return an error so this node announcement can be rejected. // return an error so this node announcement can be rejected.
dataHash := chainhash.DoubleHashB(data) dataHash := chainhash.DoubleHashB(data)
if !a.Signature.Verify(dataHash, copyPubKey(a.NodeID)) { if !nodeSig.Verify(dataHash, nodeKey) {
var msgBuf bytes.Buffer var msgBuf bytes.Buffer
if _, err := lnwire.WriteMessage(&msgBuf, a, 0); err != nil { if _, err := lnwire.WriteMessage(&msgBuf, a, 0); err != nil {
return err return err
} }
return errors.Errorf("signature on NodeAnnouncement(%x) is "+ return errors.Errorf("signature on NodeAnnouncement(%x) is "+
"invalid: %x", a.NodeID.SerializeCompressed(), "invalid: %x", nodeKey.SerializeCompressed(),
msgBuf.Bytes()) msgBuf.Bytes())
} }
@ -90,7 +132,12 @@ func ValidateChannelUpdateAnn(pubKey *btcec.PublicKey,
} }
dataHash := chainhash.DoubleHashB(data) dataHash := chainhash.DoubleHashB(data)
if !a.Signature.Verify(dataHash, copyPubKey(pubKey)) { nodeSig, err := a.Signature.ToSignature()
if err != nil {
return err
}
if !nodeSig.Verify(dataHash, pubKey) {
return errors.Errorf("invalid signature for channel "+ return errors.Errorf("invalid signature for channel "+
"update %v", spew.Sdump(a)) "update %v", spew.Sdump(a))
} }

@ -157,17 +157,17 @@ type AuthenticatedGossiper struct {
// TODO(roasbeef): limit premature networkMsgs to N // TODO(roasbeef): limit premature networkMsgs to N
prematureAnnouncements map[uint32][]*networkMsg prematureAnnouncements map[uint32][]*networkMsg
// prematureChannelUpdates is a map of ChannelUpdates we have // prematureChannelUpdates is a map of ChannelUpdates we have received
// received that wasn't associated with any channel we know about. // that wasn't associated with any channel we know about. We store
// We store them temporarily, such that we can reprocess them when // them temporarily, such that we can reprocess them when a
// a ChannelAnnouncement for the channel is received. // ChannelAnnouncement for the channel is received.
prematureChannelUpdates map[uint64][]*networkMsg prematureChannelUpdates map[uint64][]*networkMsg
pChanUpdMtx sync.Mutex pChanUpdMtx sync.Mutex
// waitingProofs is a persistent storage of partial channel proof // waitingProofs is a persistent storage of partial channel proof
// announcement messages. We use it to buffer half of the material // announcement messages. We use it to buffer half of the material
// needed to reconstruct a full authenticated channel announcement. Once // needed to reconstruct a full authenticated channel announcement.
// we receive the other half the channel proof, we'll be able to // Once we receive the other half the channel proof, we'll be able to
// properly validate it an re-broadcast it out to the network. // properly validate it an re-broadcast it out to the network.
waitingProofs *channeldb.WaitingProofStore waitingProofs *channeldb.WaitingProofStore
@ -176,8 +176,8 @@ type AuthenticatedGossiper struct {
// networkHandler. // networkHandler.
networkMsgs chan *networkMsg networkMsgs chan *networkMsg
// chanPolicyUpdates is a channel that requests to update the forwarding // chanPolicyUpdates is a channel that requests to update the
// policy of a set of channels is sent over. // forwarding policy of a set of channels is sent over.
chanPolicyUpdates chan *chanPolicyUpdateRequest chanPolicyUpdates chan *chanPolicyUpdateRequest
// bestHeight is the height of the block at the tip of the main chain // bestHeight is the height of the block at the tip of the main chain
@ -193,6 +193,9 @@ type AuthenticatedGossiper struct {
// consistent between when the DB is first read until it's written. // consistent between when the DB is first read until it's written.
channelMtx *multimutex.Mutex channelMtx *multimutex.Mutex
rejectMtx sync.RWMutex
recentRejects map[uint64]struct{}
sync.Mutex sync.Mutex
} }
@ -214,6 +217,7 @@ func New(cfg Config, selfKey *btcec.PublicKey) (*AuthenticatedGossiper, error) {
prematureChannelUpdates: make(map[uint64][]*networkMsg), prematureChannelUpdates: make(map[uint64][]*networkMsg),
waitingProofs: storage, waitingProofs: storage,
channelMtx: multimutex.NewMutex(), channelMtx: multimutex.NewMutex(),
recentRejects: make(map[uint64]struct{}),
}, nil }, nil
} }
@ -232,17 +236,22 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// containing all the messages to be sent to the target peer. // containing all the messages to be sent to the target peer.
var announceMessages []lnwire.Message var announceMessages []lnwire.Message
makeNodeAnn := func(n *channeldb.LightningNode) *lnwire.NodeAnnouncement { makeNodeAnn := func(n *channeldb.LightningNode) (*lnwire.NodeAnnouncement, error) {
alias, _ := lnwire.NewNodeAlias(n.Alias) alias, _ := lnwire.NewNodeAlias(n.Alias)
wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes)
if err != nil {
return nil, err
}
return &lnwire.NodeAnnouncement{ return &lnwire.NodeAnnouncement{
Signature: n.AuthSig, Signature: wireSig,
Timestamp: uint32(n.LastUpdate.Unix()), Timestamp: uint32(n.LastUpdate.Unix()),
Addresses: n.Addresses, Addresses: n.Addresses,
NodeID: n.PubKey, NodeID: n.PubKeyBytes,
Features: n.Features.RawFeatureVector, Features: n.Features.RawFeatureVector,
RGBColor: n.Color, RGBColor: n.Color,
Alias: alias, Alias: alias,
} }, nil
} }
// As peers are expecting channel announcements before node // As peers are expecting channel announcements before node
@ -262,8 +271,12 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// also has known validated nodes, then we'll send that as // also has known validated nodes, then we'll send that as
// well. // well.
if chanInfo.AuthProof != nil { if chanInfo.AuthProof != nil {
chanAnn, e1Ann, e2Ann := createChanAnnouncement( chanAnn, e1Ann, e2Ann, err := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2) chanInfo.AuthProof, chanInfo, e1, e2,
)
if err != nil {
return err
}
announceMessages = append(announceMessages, chanAnn) announceMessages = append(announceMessages, chanAnn)
if e1Ann != nil { if e1Ann != nil {
@ -272,7 +285,10 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// If this edge has a validated node // If this edge has a validated node
// announcement, then we'll send that as well. // announcement, then we'll send that as well.
if e1.Node.HaveNodeAnnouncement { if e1.Node.HaveNodeAnnouncement {
nodeAnn := makeNodeAnn(e1.Node) nodeAnn, err := makeNodeAnn(e1.Node)
if err != nil {
return err
}
announceMessages = append( announceMessages = append(
announceMessages, nodeAnn, announceMessages, nodeAnn,
) )
@ -285,7 +301,10 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// If this edge has a validated node // If this edge has a validated node
// announcement, then we'll send that as well. // announcement, then we'll send that as well.
if e2.Node.HaveNodeAnnouncement { if e2.Node.HaveNodeAnnouncement {
nodeAnn := makeNodeAnn(e2.Node) nodeAnn, err := makeNodeAnn(e2.Node)
if err != nil {
return err
}
announceMessages = append( announceMessages = append(
announceMessages, nodeAnn, announceMessages, nodeAnn,
) )
@ -588,7 +607,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
// NodeID to create the corresponding Vertex. // NodeID to create the corresponding Vertex.
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
sender := routing.NewVertex(message.peer) sender := routing.NewVertex(message.peer)
deDupKey := routing.NewVertex(msg.NodeID) deDupKey := routing.Vertex(msg.NodeID)
// We do the same for node announcements as we did for channel // We do the same for node announcements as we did for channel
// updates, as they also carry a timestamp. // updates, as they also carry a timestamp.
@ -875,6 +894,13 @@ func (d *AuthenticatedGossiper) networkHandler() {
continue continue
} }
// If this message was recently rejected, then we won't
// attempt to re-process it.
if d.isRecentlyRejectedMsg(announcement.msg) {
announcement.err <- fmt.Errorf("recently rejected")
continue
}
// We'll set up any dependent, and wait until a free // We'll set up any dependent, and wait until a free
// slot for this job opens up, this allow us to not // slot for this job opens up, this allow us to not
// have thousands of goroutines active. // have thousands of goroutines active.
@ -999,6 +1025,26 @@ func (d *AuthenticatedGossiper) networkHandler() {
} }
} }
// isRecentlyRejectedMsg returns true if we recently rejected a message, and
// false otherwise, This avoids expensive reprocessing of the message.
func (d *AuthenticatedGossiper) isRecentlyRejectedMsg(msg lnwire.Message) bool {
d.rejectMtx.RLock()
defer d.rejectMtx.RUnlock()
switch m := msg.(type) {
case *lnwire.ChannelUpdate:
_, ok := d.recentRejects[m.ShortChannelID.ToUint64()]
return ok
case *lnwire.ChannelAnnouncement:
_, ok := d.recentRejects[m.ShortChannelID.ToUint64()]
return ok
default:
return false
}
}
// retransmitStaleChannels examines all outgoing channels that the source node // retransmitStaleChannels examines all outgoing channels that the source node
// is known to maintain to check to see if any of them are "stale". A channel // is known to maintain to check to see if any of them are "stale". A channel
// is stale iff, the last timestamp of its rebroadcast is older then // is stale iff, the last timestamp of its rebroadcast is older then
@ -1182,9 +1228,12 @@ func (d *AuthenticatedGossiper) processRejectedEdge(chanAnnMsg *lnwire.ChannelAn
// We'll then create then validate the new fully assembled // We'll then create then validate the new fully assembled
// announcement. // announcement.
chanAnn, e1Ann, e2Ann := createChanAnnouncement( chanAnn, e1Ann, e2Ann, err := createChanAnnouncement(
proof, chanInfo, e1, e2, proof, chanInfo, e1, e2,
) )
if err != nil {
return nil, err
}
err = ValidateChannelAnn(chanAnn) err = ValidateChannelAnn(chanAnn)
if err != nil { if err != nil {
err := errors.Errorf("assembled channel announcement proof "+ err := errors.Errorf("assembled channel announcement proof "+
@ -1265,9 +1314,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Unix(int64(msg.Timestamp), 0), LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Addresses: msg.Addresses, Addresses: msg.Addresses,
PubKey: msg.NodeID, PubKeyBytes: msg.NodeID,
Alias: msg.Alias.String(), Alias: msg.Alias.String(),
AuthSig: msg.Signature, AuthSigBytes: msg.Signature.ToSignatureBytes(),
Features: features, Features: features,
Color: msg.RGBColor, Color: msg.RGBColor,
} }
@ -1307,6 +1356,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
log.Error("Ignoring ChannelAnnouncement from "+ log.Error("Ignoring ChannelAnnouncement from "+
"chain=%v, gossiper on chain=%v", msg.ChainHash, "chain=%v, gossiper on chain=%v", msg.ChainHash,
d.cfg.ChainHash) d.cfg.ChainHash)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil return nil
} }
@ -1338,6 +1390,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if err := ValidateChannelAnn(msg); err != nil { if err := ValidateChannelAnn(msg); err != nil {
err := errors.Errorf("unable to validate "+ err := errors.Errorf("unable to validate "+
"announcement: %v", err) "announcement: %v", err)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
log.Error(err) log.Error(err)
nMsg.err <- err nMsg.err <- err
@ -1348,10 +1403,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
// itself to the database so we can fetch it later when // itself to the database so we can fetch it later when
// gossiping with other nodes. // gossiping with other nodes.
proof = &channeldb.ChannelAuthProof{ proof = &channeldb.ChannelAuthProof{
NodeSig1: msg.NodeSig1, NodeSig1Bytes: msg.NodeSig1.ToSignatureBytes(),
NodeSig2: msg.NodeSig2, NodeSig2Bytes: msg.NodeSig2.ToSignatureBytes(),
BitcoinSig1: msg.BitcoinSig1, BitcoinSig1Bytes: msg.BitcoinSig1.ToSignatureBytes(),
BitcoinSig2: msg.BitcoinSig2, BitcoinSig2Bytes: msg.BitcoinSig2.ToSignatureBytes(),
} }
} }
@ -1365,14 +1420,14 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
} }
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: msg.ShortChannelID.ToUint64(), ChannelID: msg.ShortChannelID.ToUint64(),
ChainHash: msg.ChainHash, ChainHash: msg.ChainHash,
NodeKey1: msg.NodeID1, NodeKey1Bytes: msg.NodeID1,
NodeKey2: msg.NodeID2, NodeKey2Bytes: msg.NodeID2,
BitcoinKey1: msg.BitcoinKey1, BitcoinKey1Bytes: msg.BitcoinKey1,
BitcoinKey2: msg.BitcoinKey2, BitcoinKey2Bytes: msg.BitcoinKey2,
AuthProof: proof, AuthProof: proof,
Features: featureBuf.Bytes(), Features: featureBuf.Bytes(),
} }
// We will add the edge to the channel router. If the nodes // We will add the edge to the channel router. If the nodes
@ -1398,6 +1453,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
// see if we get any new announcements. // see if we get any new announcements.
anns, rErr := d.processRejectedEdge(msg, proof) anns, rErr := d.processRejectedEdge(msg, proof)
if rErr != nil { if rErr != nil {
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
nMsg.err <- rErr nMsg.err <- rErr
return nil return nil
} }
@ -1499,6 +1557,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
log.Error("Ignoring ChannelUpdate from "+ log.Error("Ignoring ChannelUpdate from "+
"chain=%v, gossiper on chain=%v", msg.ChainHash, "chain=%v, gossiper on chain=%v", msg.ChainHash,
d.cfg.ChainHash) d.cfg.ChainHash)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil return nil
} }
@ -1560,7 +1621,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
d.prematureChannelUpdates[shortChanID], d.prematureChannelUpdates[shortChanID],
nMsg) nMsg)
d.pChanUpdMtx.Unlock() d.pChanUpdMtx.Unlock()
log.Infof("Got ChannelUpdate for edge not "+ log.Debugf("Got ChannelUpdate for edge not "+
"found in graph(shortChanID=%v), "+ "found in graph(shortChanID=%v), "+
"saving for reprocessing later", "saving for reprocessing later",
shortChanID) shortChanID)
@ -1572,6 +1633,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
shortChanID, err) shortChanID, err)
log.Error(err) log.Error(err)
nMsg.err <- err nMsg.err <- err
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil return nil
} }
} }
@ -1582,9 +1647,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
var pubKey *btcec.PublicKey var pubKey *btcec.PublicKey
switch { switch {
case msg.Flags&lnwire.ChanUpdateDirection == 0: case msg.Flags&lnwire.ChanUpdateDirection == 0:
pubKey = chanInfo.NodeKey1 pubKey, _ = chanInfo.NodeKey1()
case msg.Flags&lnwire.ChanUpdateDirection == 1: case msg.Flags&lnwire.ChanUpdateDirection == 1:
pubKey = chanInfo.NodeKey2 pubKey, _ = chanInfo.NodeKey2()
} }
// Validate the channel announcement with the expected public // Validate the channel announcement with the expected public
@ -1601,7 +1666,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
} }
update := &channeldb.ChannelEdgePolicy{ update := &channeldb.ChannelEdgePolicy{
Signature: msg.Signature, SigBytes: msg.Signature.ToSignatureBytes(),
ChannelID: shortChanID, ChannelID: shortChanID,
LastUpdate: time.Unix(int64(msg.Timestamp), 0), LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Flags: msg.Flags, Flags: msg.Flags,
@ -1615,6 +1680,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if routing.IsError(err, routing.ErrOutdated, routing.ErrIgnored) { if routing.IsError(err, routing.ErrOutdated, routing.ErrIgnored) {
log.Debug(err) log.Debug(err)
} else { } else {
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
log.Error(err) log.Error(err)
} }
@ -1632,9 +1700,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
var remotePeer *btcec.PublicKey var remotePeer *btcec.PublicKey
switch { switch {
case msg.Flags&lnwire.ChanUpdateDirection == 0: case msg.Flags&lnwire.ChanUpdateDirection == 0:
remotePeer = chanInfo.NodeKey2 remotePeer, _ = chanInfo.NodeKey2()
case msg.Flags&lnwire.ChanUpdateDirection == 1: case msg.Flags&lnwire.ChanUpdateDirection == 1:
remotePeer = chanInfo.NodeKey1 remotePeer, _ = chanInfo.NodeKey1()
} }
// Send ChannelUpdate directly to remotePeer. // Send ChannelUpdate directly to remotePeer.
@ -1726,9 +1794,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
} }
isFirstNode := bytes.Equal(nMsg.peer.SerializeCompressed(), isFirstNode := bytes.Equal(nMsg.peer.SerializeCompressed(),
chanInfo.NodeKey1.SerializeCompressed()) chanInfo.NodeKey1Bytes[:])
isSecondNode := bytes.Equal(nMsg.peer.SerializeCompressed(), isSecondNode := bytes.Equal(nMsg.peer.SerializeCompressed(),
chanInfo.NodeKey2.SerializeCompressed()) chanInfo.NodeKey2Bytes[:])
// Ensure that channel that was retrieved belongs to the peer // Ensure that channel that was retrieved belongs to the peer
// which sent the proof announcement. // which sent the proof announcement.
@ -1748,9 +1816,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if !nMsg.isRemote { if !nMsg.isRemote {
var remotePeer *btcec.PublicKey var remotePeer *btcec.PublicKey
if isFirstNode { if isFirstNode {
remotePeer = chanInfo.NodeKey2 remotePeer, _ = chanInfo.NodeKey2()
} else { } else {
remotePeer = chanInfo.NodeKey1 remotePeer, _ = chanInfo.NodeKey1()
} }
// Since the remote peer might not be online // Since the remote peer might not be online
// we'll call a method that will attempt to // we'll call a method that will attempt to
@ -1786,9 +1854,14 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
msg.ChannelID, msg.ChannelID,
peerID) peerID)
chanAnn, _, _ := createChanAnnouncement( chanAnn, _, _, err := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2) chanInfo.AuthProof, chanInfo, e1, e2,
err := d.cfg.SendToPeer(nMsg.peer, chanAnn) )
if err != nil {
log.Errorf("unable to gen ann: %v", err)
return
}
err = d.cfg.SendToPeer(nMsg.peer, chanAnn)
if err != nil { if err != nil {
log.Errorf("Failed sending "+ log.Errorf("Failed sending "+
"full proof to "+ "full proof to "+
@ -1846,17 +1919,22 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
// validate it shortly below. // validate it shortly below.
var dbProof channeldb.ChannelAuthProof var dbProof channeldb.ChannelAuthProof
if isFirstNode { if isFirstNode {
dbProof.NodeSig1 = msg.NodeSignature dbProof.NodeSig1Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2 = oppositeProof.NodeSignature dbProof.NodeSig2Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1 = msg.BitcoinSignature dbProof.BitcoinSig1Bytes = msg.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2 = oppositeProof.BitcoinSignature dbProof.BitcoinSig2Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
} else { } else {
dbProof.NodeSig1 = oppositeProof.NodeSignature dbProof.NodeSig1Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2 = msg.NodeSignature dbProof.NodeSig2Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1 = oppositeProof.BitcoinSignature dbProof.BitcoinSig1Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2 = msg.BitcoinSignature dbProof.BitcoinSig2Bytes = msg.BitcoinSignature.ToSignatureBytes()
}
chanAnn, e1Ann, e2Ann, err := createChanAnnouncement(&dbProof, chanInfo, e1, e2)
if err != nil {
log.Error(err)
nMsg.err <- err
return nil
} }
chanAnn, e1Ann, e2Ann := createChanAnnouncement(&dbProof, chanInfo, e1, e2)
// With all the necessary components assembled validate the // With all the necessary components assembled validate the
// full channel announcement proof. // full channel announcement proof.
@ -2017,6 +2095,8 @@ func (d *AuthenticatedGossiper) sendAnnSigReliably(
func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
edge *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate, error) { edge *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate, error) {
var err error
// Make sure timestamp is always increased, such that our update // Make sure timestamp is always increased, such that our update
// gets propagated. // gets propagated.
timestamp := time.Now().Unix() timestamp := time.Now().Unix()
@ -2025,7 +2105,6 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
} }
edge.LastUpdate = time.Unix(timestamp, 0) edge.LastUpdate = time.Unix(timestamp, 0)
chanUpdate := &lnwire.ChannelUpdate{ chanUpdate := &lnwire.ChannelUpdate{
Signature: edge.Signature,
ChainHash: info.ChainHash, ChainHash: info.ChainHash,
ShortChannelID: lnwire.NewShortChanIDFromInt(edge.ChannelID), ShortChannelID: lnwire.NewShortChanIDFromInt(edge.ChannelID),
Timestamp: uint32(timestamp), Timestamp: uint32(timestamp),
@ -2035,6 +2114,10 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
BaseFee: uint32(edge.FeeBaseMSat), BaseFee: uint32(edge.FeeBaseMSat),
FeeRate: uint32(edge.FeeProportionalMillionths), FeeRate: uint32(edge.FeeProportionalMillionths),
} }
chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(edge.SigBytes)
if err != nil {
return nil, nil, err
}
// With the update applied, we'll generate a new signature over a // With the update applied, we'll generate a new signature over a
// digest of the channel announcement itself. // digest of the channel announcement itself.
@ -2045,8 +2128,11 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
// Next, we'll set the new signature in place, and update the reference // Next, we'll set the new signature in place, and update the reference
// in the backing slice. // in the backing slice.
edge.Signature = sig edge.SigBytes = sig.Serialize()
chanUpdate.Signature = sig chanUpdate.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, nil, err
}
// To ensure that our signature is valid, we'll verify it ourself // To ensure that our signature is valid, we'll verify it ourself
// before committing it to the slice returned. // before committing it to the slice returned.
@ -2057,7 +2143,6 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
} }
// Finally, we'll write the new edge policy to disk. // Finally, we'll write the new edge policy to disk.
edge.Node.PubKey.Curve = nil
if err := d.cfg.Router.UpdateEdge(edge); err != nil { if err := d.cfg.Router.UpdateEdge(edge); err != nil {
return nil, nil, err return nil, nil, err
} }
@ -2069,17 +2154,37 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
if info.AuthProof != nil { if info.AuthProof != nil {
chanID := lnwire.NewShortChanIDFromInt(info.ChannelID) chanID := lnwire.NewShortChanIDFromInt(info.ChannelID)
chanAnn = &lnwire.ChannelAnnouncement{ chanAnn = &lnwire.ChannelAnnouncement{
NodeSig1: info.AuthProof.NodeSig1,
NodeSig2: info.AuthProof.NodeSig2,
ShortChannelID: chanID, ShortChannelID: chanID,
BitcoinSig1: info.AuthProof.BitcoinSig1, NodeID1: info.NodeKey1Bytes,
BitcoinSig2: info.AuthProof.BitcoinSig2, NodeID2: info.NodeKey2Bytes,
NodeID1: info.NodeKey1,
NodeID2: info.NodeKey2,
ChainHash: info.ChainHash, ChainHash: info.ChainHash,
BitcoinKey1: info.BitcoinKey1, BitcoinKey1: info.BitcoinKey1Bytes,
Features: lnwire.NewRawFeatureVector(), Features: lnwire.NewRawFeatureVector(),
BitcoinKey2: info.BitcoinKey2, BitcoinKey2: info.BitcoinKey2Bytes,
}
chanAnn.NodeSig1, err = lnwire.NewSigFromRawSignature(
info.AuthProof.NodeSig1Bytes,
)
if err != nil {
return nil, nil, err
}
chanAnn.NodeSig2, err = lnwire.NewSigFromRawSignature(
info.AuthProof.NodeSig2Bytes,
)
if err != nil {
return nil, nil, err
}
chanAnn.BitcoinSig1, err = lnwire.NewSigFromRawSignature(
info.AuthProof.BitcoinSig1Bytes,
)
if err != nil {
return nil, nil, err
}
chanAnn.BitcoinSig2, err = lnwire.NewSigFromRawSignature(
info.AuthProof.BitcoinSig2Bytes,
)
if err != nil {
return nil, nil, err
} }
} }

@ -305,10 +305,6 @@ func createAnnouncements(blockHeight uint32) (*annBatch, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
batch.localChanAnn.BitcoinSig1 = nil
batch.localChanAnn.BitcoinSig2 = nil
batch.localChanAnn.NodeSig1 = nil
batch.localChanAnn.NodeSig2 = nil
batch.chanUpdAnn1, err = createUpdateAnnouncement( batch.chanUpdAnn1, err = createUpdateAnnouncement(
blockHeight, 0, nodeKeyPriv1, timestamp, blockHeight, 0, nodeKeyPriv1, timestamp,
@ -342,13 +338,18 @@ func createNodeAnnouncement(priv *btcec.PrivateKey,
a := &lnwire.NodeAnnouncement{ a := &lnwire.NodeAnnouncement{
Timestamp: timestamp, Timestamp: timestamp,
Addresses: testAddrs, Addresses: testAddrs,
NodeID: priv.PubKey(),
Alias: alias, Alias: alias,
Features: testFeatures, Features: testFeatures,
} }
copy(a.NodeID[:], priv.PubKey().SerializeCompressed())
signer := mockSigner{priv} signer := mockSigner{priv}
a.Signature, err = SignAnnouncement(&signer, priv.PubKey(), a) sig, err := SignAnnouncement(&signer, priv.PubKey(), a)
if err != nil {
return nil, err
}
a.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -376,7 +377,13 @@ func createUpdateAnnouncement(blockHeight uint32, flags lnwire.ChanUpdateFlag,
pub := nodeKey.PubKey() pub := nodeKey.PubKey()
signer := mockSigner{nodeKey} signer := mockSigner{nodeKey}
if a.Signature, err = SignAnnouncement(&signer, pub, a); err != nil { sig, err := SignAnnouncement(&signer, pub, a)
if err != nil {
return nil, err
}
a.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, err return nil, err
} }
@ -392,34 +399,54 @@ func createRemoteChannelAnnouncement(blockHeight uint32) (*lnwire.ChannelAnnounc
TxIndex: 0, TxIndex: 0,
TxPosition: 0, TxPosition: 0,
}, },
NodeID1: nodeKeyPub1, Features: testFeatures,
NodeID2: nodeKeyPub2,
BitcoinKey1: bitcoinKeyPub1,
BitcoinKey2: bitcoinKeyPub2,
Features: testFeatures,
} }
copy(a.NodeID1[:], nodeKeyPub1.SerializeCompressed())
copy(a.NodeID2[:], nodeKeyPub2.SerializeCompressed())
copy(a.BitcoinKey1[:], bitcoinKeyPub1.SerializeCompressed())
copy(a.BitcoinKey2[:], bitcoinKeyPub2.SerializeCompressed())
pub := nodeKeyPriv1.PubKey() pub := nodeKeyPriv1.PubKey()
signer := mockSigner{nodeKeyPriv1} signer := mockSigner{nodeKeyPriv1}
if a.NodeSig1, err = SignAnnouncement(&signer, pub, a); err != nil { sig, err := SignAnnouncement(&signer, pub, a)
if err != nil {
return nil, err
}
a.NodeSig1, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, err return nil, err
} }
pub = nodeKeyPriv2.PubKey() pub = nodeKeyPriv2.PubKey()
signer = mockSigner{nodeKeyPriv2} signer = mockSigner{nodeKeyPriv2}
if a.NodeSig2, err = SignAnnouncement(&signer, pub, a); err != nil { sig, err = SignAnnouncement(&signer, pub, a)
if err != nil {
return nil, err
}
a.NodeSig2, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, err return nil, err
} }
pub = bitcoinKeyPriv1.PubKey() pub = bitcoinKeyPriv1.PubKey()
signer = mockSigner{bitcoinKeyPriv1} signer = mockSigner{bitcoinKeyPriv1}
if a.BitcoinSig1, err = SignAnnouncement(&signer, pub, a); err != nil { sig, err = SignAnnouncement(&signer, pub, a)
if err != nil {
return nil, err
}
a.BitcoinSig1, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, err return nil, err
} }
pub = bitcoinKeyPriv2.PubKey() pub = bitcoinKeyPriv2.PubKey()
signer = mockSigner{bitcoinKeyPriv2} signer = mockSigner{bitcoinKeyPriv2}
if a.BitcoinSig2, err = SignAnnouncement(&signer, pub, a); err != nil { sig, err = SignAnnouncement(&signer, pub, a)
if err != nil {
return nil, err
}
a.BitcoinSig2, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, err return nil, err
} }
@ -521,8 +548,10 @@ func TestProcessAnnouncement(t *testing.T) {
t.Fatalf("can't create node announcement: %v", err) t.Fatalf("can't create node announcement: %v", err)
} }
nodePub := nodeKeyPriv1.PubKey()
select { select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(na, na.NodeID): case err = <-ctx.gossiper.ProcessRemoteAnnouncement(na, nodePub):
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed") t.Fatal("remote announcement not processed")
} }
@ -532,7 +561,7 @@ func TestProcessAnnouncement(t *testing.T) {
select { select {
case msg := <-ctx.broadcastedMessage: case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg) assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay): case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded") t.Fatal("announcement wasn't proceeded")
} }
@ -550,7 +579,7 @@ func TestProcessAnnouncement(t *testing.T) {
} }
select { select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ca, na.NodeID): case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ca, nodePub):
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed") t.Fatal("remote announcement not processed")
} }
@ -560,7 +589,7 @@ func TestProcessAnnouncement(t *testing.T) {
select { select {
case msg := <-ctx.broadcastedMessage: case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg) assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay): case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded") t.Fatal("announcement wasn't proceeded")
} }
@ -578,7 +607,7 @@ func TestProcessAnnouncement(t *testing.T) {
} }
select { select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ua, na.NodeID): case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ua, nodePub):
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed") t.Fatal("remote announcement not processed")
} }
@ -588,7 +617,7 @@ func TestProcessAnnouncement(t *testing.T) {
select { select {
case msg := <-ctx.broadcastedMessage: case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg) assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay): case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded") t.Fatal("announcement wasn't proceeded")
} }
@ -612,11 +641,13 @@ func TestPrematureAnnouncement(t *testing.T) {
} }
defer cleanup() defer cleanup()
na, err := createNodeAnnouncement(nodeKeyPriv1, timestamp) _, err = createNodeAnnouncement(nodeKeyPriv1, timestamp)
if err != nil { if err != nil {
t.Fatalf("can't create node announcement: %v", err) t.Fatalf("can't create node announcement: %v", err)
} }
nodePub := nodeKeyPriv1.PubKey()
// Pretending that we receive the valid channel announcement from // Pretending that we receive the valid channel announcement from
// remote side, but block height of this announcement is greater than // remote side, but block height of this announcement is greater than
// highest know to us, for that reason it should be added to the // highest know to us, for that reason it should be added to the
@ -627,7 +658,7 @@ func TestPrematureAnnouncement(t *testing.T) {
} }
select { select {
case <-ctx.gossiper.ProcessRemoteAnnouncement(ca, na.NodeID): case <-ctx.gossiper.ProcessRemoteAnnouncement(ca, nodePub):
t.Fatal("announcement was proceeded") t.Fatal("announcement was proceeded")
case <-time.After(100 * time.Millisecond): case <-time.After(100 * time.Millisecond):
} }
@ -646,7 +677,7 @@ func TestPrematureAnnouncement(t *testing.T) {
} }
select { select {
case <-ctx.gossiper.ProcessRemoteAnnouncement(ua, na.NodeID): case <-ctx.gossiper.ProcessRemoteAnnouncement(ua, nodePub):
t.Fatal("announcement was proceeded") t.Fatal("announcement was proceeded")
case <-time.After(100 * time.Millisecond): case <-time.After(100 * time.Millisecond):
} }
@ -709,8 +740,14 @@ func TestSignatureAnnouncementLocalFirst(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Recreate lightning network topology. Initialize router with channel // Recreate lightning network topology. Initialize router with channel
// between two nodes. // between two nodes.
@ -865,8 +902,14 @@ func TestOrphanSignatureAnnouncement(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Pretending that we receive local channel announcement from funding // Pretending that we receive local channel announcement from funding
// manager, thereby kick off the announcement exchange process, in // manager, thereby kick off the announcement exchange process, in
@ -1021,8 +1064,14 @@ func TestSignatureAnnouncementRetry(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Recreate lightning network topology. Initialize router with channel // Recreate lightning network topology. Initialize router with channel
// between two nodes. // between two nodes.
@ -1203,8 +1252,14 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Recreate lightning network topology. Initialize router with channel // Recreate lightning network topology. Initialize router with channel
// between two nodes. // between two nodes.
@ -1422,8 +1477,14 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Recreate lightning network topology. Initialize router with channel // Recreate lightning network topology. Initialize router with channel
// between two nodes. // between two nodes.
@ -1819,8 +1880,14 @@ func TestReceiveRemoteChannelUpdateFirst(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err) t.Fatalf("can't generate announcements: %v", err)
} }
localKey := batch.nodeAnn1.NodeID localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
remoteKey := batch.nodeAnn2.NodeID if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
remoteKey, err := btcec.ParsePubKey(batch.nodeAnn2.NodeID[:], btcec.S256())
if err != nil {
t.Fatalf("unable to parse pubkey: %v", err)
}
// Recreate the case where the remote node is sending us its ChannelUpdate // Recreate the case where the remote node is sending us its ChannelUpdate
// before we have been able to process our own ChannelAnnouncement and // before we have been able to process our own ChannelAnnouncement and

@ -16,24 +16,46 @@ import (
func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof, func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
chanInfo *channeldb.ChannelEdgeInfo, chanInfo *channeldb.ChannelEdgeInfo,
e1, e2 *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, e1, e2 *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement,
*lnwire.ChannelUpdate, *lnwire.ChannelUpdate) { *lnwire.ChannelUpdate, *lnwire.ChannelUpdate, error) {
// First, using the parameters of the channel, along with the channel // First, using the parameters of the channel, along with the channel
// authentication chanProof, we'll create re-create the original // authentication chanProof, we'll create re-create the original
// authenticated channel announcement. // authenticated channel announcement.
chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID) chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
chanAnn := &lnwire.ChannelAnnouncement{ chanAnn := &lnwire.ChannelAnnouncement{
NodeSig1: chanProof.NodeSig1,
NodeSig2: chanProof.NodeSig2,
ShortChannelID: chanID, ShortChannelID: chanID,
BitcoinSig1: chanProof.BitcoinSig1, NodeID1: chanInfo.NodeKey1Bytes,
BitcoinSig2: chanProof.BitcoinSig2, NodeID2: chanInfo.NodeKey2Bytes,
NodeID1: chanInfo.NodeKey1,
NodeID2: chanInfo.NodeKey2,
ChainHash: chanInfo.ChainHash, ChainHash: chanInfo.ChainHash,
BitcoinKey1: chanInfo.BitcoinKey1, BitcoinKey1: chanInfo.BitcoinKey1Bytes,
BitcoinKey2: chanInfo.BitcoinKey2Bytes,
Features: lnwire.NewRawFeatureVector(), Features: lnwire.NewRawFeatureVector(),
BitcoinKey2: chanInfo.BitcoinKey2, }
var err error
chanAnn.BitcoinSig1, err = lnwire.NewSigFromRawSignature(
chanProof.BitcoinSig1Bytes,
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.BitcoinSig2, err = lnwire.NewSigFromRawSignature(
chanProof.BitcoinSig2Bytes,
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.NodeSig1, err = lnwire.NewSigFromRawSignature(
chanProof.NodeSig1Bytes,
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.NodeSig2, err = lnwire.NewSigFromRawSignature(
chanProof.NodeSig2Bytes,
)
if err != nil {
return nil, nil, nil, err
} }
// We'll unconditionally queue the channel's existence chanProof as it // We'll unconditionally queue the channel's existence chanProof as it
@ -46,7 +68,6 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
var edge1Ann, edge2Ann *lnwire.ChannelUpdate var edge1Ann, edge2Ann *lnwire.ChannelUpdate
if e1 != nil { if e1 != nil {
edge1Ann = &lnwire.ChannelUpdate{ edge1Ann = &lnwire.ChannelUpdate{
Signature: e1.Signature,
ChainHash: chanInfo.ChainHash, ChainHash: chanInfo.ChainHash,
ShortChannelID: chanID, ShortChannelID: chanID,
Timestamp: uint32(e1.LastUpdate.Unix()), Timestamp: uint32(e1.LastUpdate.Unix()),
@ -56,10 +77,13 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
BaseFee: uint32(e1.FeeBaseMSat), BaseFee: uint32(e1.FeeBaseMSat),
FeeRate: uint32(e1.FeeProportionalMillionths), FeeRate: uint32(e1.FeeProportionalMillionths),
} }
edge1Ann.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes)
if err != nil {
return nil, nil, nil, err
}
} }
if e2 != nil { if e2 != nil {
edge2Ann = &lnwire.ChannelUpdate{ edge2Ann = &lnwire.ChannelUpdate{
Signature: e2.Signature,
ChainHash: chanInfo.ChainHash, ChainHash: chanInfo.ChainHash,
ShortChannelID: chanID, ShortChannelID: chanID,
Timestamp: uint32(e2.LastUpdate.Unix()), Timestamp: uint32(e2.LastUpdate.Unix()),
@ -69,9 +93,13 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
BaseFee: uint32(e2.FeeBaseMSat), BaseFee: uint32(e2.FeeBaseMSat),
FeeRate: uint32(e2.FeeProportionalMillionths), FeeRate: uint32(e2.FeeProportionalMillionths),
} }
edge2Ann.Signature, err = lnwire.NewSigFromRawSignature(e2.SigBytes)
if err != nil {
return nil, nil, nil, err
}
} }
return chanAnn, edge1Ann, edge2Ann return chanAnn, edge1Ann, edge2Ann, nil
} }
// copyPubKey performs a copy of the target public key, setting a fresh curve // copyPubKey performs a copy of the target public key, setting a fresh curve

@ -1062,14 +1062,6 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
// the commitment transaction to the remote peer. // the commitment transaction to the remote peer.
outPoint := resCtx.reservation.FundingOutpoint() outPoint := resCtx.reservation.FundingOutpoint()
_, sig := resCtx.reservation.OurSignatures() _, sig := resCtx.reservation.OurSignatures()
commitSig, err := btcec.ParseSignature(sig, btcec.S256())
if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey,
msg.PendingChannelID, []byte(err.Error()))
resCtx.err <- err
return
}
// A new channel has almost finished the funding process. In order to // A new channel has almost finished the funding process. In order to
// properly synchronize with the writeHandler goroutine, we add a new // properly synchronize with the writeHandler goroutine, we add a new
@ -1095,7 +1087,14 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fundingCreated := &lnwire.FundingCreated{ fundingCreated := &lnwire.FundingCreated{
PendingChannelID: pendingChanID, PendingChannelID: pendingChanID,
FundingPoint: *outPoint, FundingPoint: *outPoint,
CommitSig: commitSig, }
fundingCreated.CommitSig, err = lnwire.NewSigFromRawSignature(sig)
if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey,
msg.PendingChannelID, []byte(err.Error()))
resCtx.err <- err
return
} }
err = f.cfg.SendToPeer(fmsg.peerAddress.IdentityKey, fundingCreated) err = f.cfg.SendToPeer(fmsg.peerAddress.IdentityKey, fundingCreated)
if err != nil { if err != nil {
@ -1148,7 +1147,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// funding transaction will broadcast after our next message. // funding transaction will broadcast after our next message.
// CompleteReservationSingle will also mark the channel as 'IsPending' // CompleteReservationSingle will also mark the channel as 'IsPending'
// in the database. // in the database.
commitSig := fmsg.msg.CommitSig.Serialize() commitSig := fmsg.msg.CommitSig.ToSignatureBytes()
completeChan, err := resCtx.reservation.CompleteReservationSingle( completeChan, err := resCtx.reservation.CompleteReservationSingle(
&fundingOut, commitSig) &fundingOut, commitSig)
if err != nil { if err != nil {
@ -1191,11 +1190,8 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// With their signature for our version of the commitment transaction // With their signature for our version of the commitment transaction
// verified, we can now send over our signature to the remote peer. // verified, we can now send over our signature to the remote peer.
//
// TODO(roasbeef): just have raw bytes in wire msg? avoids decoding
// then decoding shortly afterwards.
_, sig := resCtx.reservation.OurSignatures() _, sig := resCtx.reservation.OurSignatures()
ourCommitSig, err := btcec.ParseSignature(sig, btcec.S256()) ourCommitSig, err := lnwire.NewSigFromRawSignature(sig)
if err != nil { if err != nil {
fndgLog.Errorf("unable to parse signature: %v", err) fndgLog.Errorf("unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peerAddress.IdentityKey,
@ -1344,7 +1340,7 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
// The remote peer has responded with a signature for our commitment // The remote peer has responded with a signature for our commitment
// transaction. We'll verify the signature for validity, then commit // transaction. We'll verify the signature for validity, then commit
// the state to disk as we can now open the channel. // the state to disk as we can now open the channel.
commitSig := fmsg.msg.CommitSig.Serialize() commitSig := fmsg.msg.CommitSig.ToSignatureBytes()
completeChan, err := resCtx.reservation.CompleteReservation(nil, commitSig) completeChan, err := resCtx.reservation.CompleteReservation(nil, commitSig)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to complete reservation sign complete: %v", err) fndgLog.Errorf("Unable to complete reservation sign complete: %v", err)
@ -2127,19 +2123,19 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey *btcec.Pu
selfBytes := localPubKey.SerializeCompressed() selfBytes := localPubKey.SerializeCompressed()
remoteBytes := remotePubKey.SerializeCompressed() remoteBytes := remotePubKey.SerializeCompressed()
if bytes.Compare(selfBytes, remoteBytes) == -1 { if bytes.Compare(selfBytes, remoteBytes) == -1 {
chanAnn.NodeID1 = localPubKey copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed())
chanAnn.NodeID2 = remotePubKey copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed())
chanAnn.BitcoinKey1 = localFundingKey copy(chanAnn.BitcoinKey1[:], localFundingKey.SerializeCompressed())
chanAnn.BitcoinKey2 = remoteFundingKey copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed())
// If we're the first node then update the chanFlags to // If we're the first node then update the chanFlags to
// indicate the "direction" of the update. // indicate the "direction" of the update.
chanFlags = 0 chanFlags = 0
} else { } else {
chanAnn.NodeID1 = remotePubKey copy(chanAnn.NodeID1[:], remotePubKey.SerializeCompressed())
chanAnn.NodeID2 = localPubKey copy(chanAnn.NodeID2[:], localPubKey.SerializeCompressed())
chanAnn.BitcoinKey1 = remoteFundingKey copy(chanAnn.BitcoinKey1[:], remoteFundingKey.SerializeCompressed())
chanAnn.BitcoinKey2 = localFundingKey copy(chanAnn.BitcoinKey2[:], localFundingKey.SerializeCompressed())
// If we're the second node then update the chanFlags to // If we're the second node then update the chanFlags to
// indicate the "direction" of the update. // indicate the "direction" of the update.
@ -2171,7 +2167,12 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey *btcec.Pu
if err != nil { if err != nil {
return nil, err return nil, err
} }
chanUpdateAnn.Signature, err = f.cfg.SignMessage(f.cfg.IDKey, chanUpdateMsg) sig, err := f.cfg.SignMessage(f.cfg.IDKey, chanUpdateMsg)
if err != nil {
return nil, errors.Errorf("unable to generate channel "+
"update announcement signature: %v", err)
}
chanUpdateAnn.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil { if err != nil {
return nil, errors.Errorf("unable to generate channel "+ return nil, errors.Errorf("unable to generate channel "+
"update announcement signature: %v", err) "update announcement signature: %v", err)
@ -2203,10 +2204,16 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey *btcec.Pu
// provide the other side with the necessary signatures required to // provide the other side with the necessary signatures required to
// allow them to reconstruct the full channel announcement. // allow them to reconstruct the full channel announcement.
proof := &lnwire.AnnounceSignatures{ proof := &lnwire.AnnounceSignatures{
ChannelID: chanID, ChannelID: chanID,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
NodeSignature: nodeSig, }
BitcoinSignature: bitcoinSig, proof.NodeSignature, err = lnwire.NewSigFromSignature(nodeSig)
if err != nil {
return nil, err
}
proof.BitcoinSignature, err = lnwire.NewSigFromSignature(bitcoinSig)
if err != nil {
return nil, err
} }
return &chanAnnouncement{ return &chanAnnouncement{

@ -5,6 +5,7 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
@ -79,6 +80,13 @@ var (
IdentityKey: bobPubKey, IdentityKey: bobPubKey,
Address: bobTCPAddr, Address: bobTCPAddr,
} }
testSig = &btcec.Signature{
R: new(big.Int),
S: new(big.Int),
}
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
) )
type mockNotifier struct { type mockNotifier struct {
@ -217,7 +225,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
Notifier: chainNotifier, Notifier: chainNotifier,
FeeEstimator: estimator, FeeEstimator: estimator,
SignMessage: func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) { SignMessage: func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) {
return nil, nil return testSig, nil
}, },
SendAnnouncement: func(msg lnwire.Message) error { SendAnnouncement: func(msg lnwire.Message) error {
select { select {
@ -319,7 +327,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
FeeEstimator: oldCfg.FeeEstimator, FeeEstimator: oldCfg.FeeEstimator,
SignMessage: func(pubKey *btcec.PublicKey, SignMessage: func(pubKey *btcec.PublicKey,
msg []byte) (*btcec.Signature, error) { msg []byte) (*btcec.Signature, error) {
return nil, nil return testSig, nil
}, },
SendAnnouncement: func(msg lnwire.Message) error { SendAnnouncement: func(msg lnwire.Message) error {
select { select {

@ -57,13 +57,6 @@ func messageToString(msg lnwire.Message) string {
switch m := msg.(type) { switch m := msg.(type) {
case *lnwire.RevokeAndAck: case *lnwire.RevokeAndAck:
m.NextRevocationKey.Curve = nil m.NextRevocationKey.Curve = nil
case *lnwire.NodeAnnouncement:
m.NodeID.Curve = nil
case *lnwire.ChannelAnnouncement:
m.NodeID1.Curve = nil
m.NodeID2.Curve = nil
m.BitcoinKey1.Curve = nil
m.BitcoinKey2.Curve = nil
case *lnwire.AcceptChannel: case *lnwire.AcceptChannel:
m.FundingKey.Curve = nil m.FundingKey.Curve = nil
m.RevocationPoint.Curve = nil m.RevocationPoint.Curve = nil

@ -48,6 +48,7 @@ var (
R: new(big.Int), R: new(big.Int),
S: new(big.Int), S: new(big.Int),
} }
wireSig, _ = lnwire.NewSigFromSignature(testSig)
_, _ = testSig.R.SetString("6372440660162918006277497454296753625158993"+ _, _ = testSig.R.SetString("6372440660162918006277497454296753625158993"+
"5445068131219452686511677818569431", 10) "5445068131219452686511677818569431", 10)
@ -55,11 +56,11 @@ var (
"3135609736119018462340006816851118", 10) "3135609736119018462340006816851118", 10)
) )
// mockGetChanUpdateMessage helper function which returns topology update // mockGetChanUpdateMessage helper function which returns topology update of
// of the channel // the channel
func mockGetChanUpdateMessage() (*lnwire.ChannelUpdate, error) { func mockGetChanUpdateMessage() (*lnwire.ChannelUpdate, error) {
return &lnwire.ChannelUpdate{ return &lnwire.ChannelUpdate{
Signature: testSig, Signature: wireSig,
}, nil }, nil
} }

@ -2557,8 +2557,8 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
// new commitment to the remote party. The commit diff returned contains all // new commitment to the remote party. The commit diff returned contains all
// information necessary for retransmission. // information necessary for retransmission.
func (lc *LightningChannel) createCommitDiff( func (lc *LightningChannel) createCommitDiff(
newCommit *commitment, commitSig *btcec.Signature, newCommit *commitment, commitSig lnwire.Sig,
htlcSigs []*btcec.Signature) (*channeldb.CommitDiff, error) { htlcSigs []lnwire.Sig) (*channeldb.CommitDiff, error) {
// First, we need to convert the funding outpoint into the ID that's // First, we need to convert the funding outpoint into the ID that's
// used on the wire to identify this channel. We'll use this shortly // used on the wire to identify this channel. We'll use this shortly
@ -2673,10 +2673,15 @@ func (lc *LightningChannel) createCommitDiff(
// itself, while the second parameter is a slice of all HTLC signatures (if // itself, while the second parameter is a slice of all HTLC signatures (if
// any). The HTLC signatures are sorted according to the BIP 69 order of the // any). The HTLC signatures are sorted according to the BIP 69 order of the
// HTLC's on the commitment transaction. // HTLC's on the commitment transaction.
func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Signature, error) { func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, error) {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
var (
sig lnwire.Sig
htlcSigs []lnwire.Sig
)
// If we're awaiting for an ACK to a commitment signature, or if we // If we're awaiting for an ACK to a commitment signature, or if we
// don't yet have the initial next revocation point of the remote // don't yet have the initial next revocation point of the remote
// party, then we're unable to create new states. Each time we create a // party, then we're unable to create new states. Each time we create a
@ -2684,7 +2689,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
commitPoint := lc.channelState.RemoteNextRevocation commitPoint := lc.channelState.RemoteNextRevocation
if lc.remoteCommitChain.hasUnackedCommitment() || commitPoint == nil { if lc.remoteCommitChain.hasUnackedCommitment() || commitPoint == nil {
return nil, nil, ErrNoWindow return sig, htlcSigs, ErrNoWindow
} }
// Determine the last update on the remote log that has been locked in. // Determine the last update on the remote log that has been locked in.
@ -2698,7 +2703,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
err := lc.validateCommitmentSanity(remoteACKedIndex, err := lc.validateCommitmentSanity(remoteACKedIndex,
lc.localUpdateLog.logIndex, false, true, true) lc.localUpdateLog.logIndex, false, true, true)
if err != nil { if err != nil {
return nil, nil, err return sig, htlcSigs, err
} }
// Grab the next commitment point for the remote party. This will be // Grab the next commitment point for the remote party. This will be
@ -2719,7 +2724,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
remoteACKedIndex, remoteHtlcIndex, keyRing, remoteACKedIndex, remoteHtlcIndex, keyRing,
) )
if err != nil { if err != nil {
return nil, nil, err return sig, htlcSigs, err
} }
walletLog.Tracef("ChannelPoint(%v): extending remote chain to height %v, "+ walletLog.Tracef("ChannelPoint(%v): extending remote chain to height %v, "+
@ -2744,7 +2749,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
lc.localChanCfg, lc.remoteChanCfg, newCommitView, lc.localChanCfg, lc.remoteChanCfg, newCommitView,
) )
if err != nil { if err != nil {
return nil, nil, err return sig, htlcSigs, err
} }
lc.sigPool.SubmitSignBatch(sigBatch) lc.sigPool.SubmitSignBatch(sigBatch)
@ -2755,12 +2760,12 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
rawSig, err := lc.signer.SignOutputRaw(newCommitView.txn, lc.signDesc) rawSig, err := lc.signer.SignOutputRaw(newCommitView.txn, lc.signDesc)
if err != nil { if err != nil {
close(cancelChan) close(cancelChan)
return nil, nil, err return sig, htlcSigs, err
} }
sig, err := btcec.ParseSignature(rawSig, btcec.S256()) sig, err = lnwire.NewSigFromRawSignature(rawSig)
if err != nil { if err != nil {
close(cancelChan) close(cancelChan)
return nil, nil, err return sig, htlcSigs, err
} }
// We'll need to send over the signatures to the remote party in the // We'll need to send over the signatures to the remote party in the
@ -2772,7 +2777,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
// With the jobs sorted, we'll now iterate through all the responses to // With the jobs sorted, we'll now iterate through all the responses to
// gather each of the signatures in order. // gather each of the signatures in order.
htlcSigs := make([]*btcec.Signature, 0, len(sigBatch)) htlcSigs = make([]lnwire.Sig, 0, len(sigBatch))
for _, htlcSigJob := range sigBatch { for _, htlcSigJob := range sigBatch {
select { select {
case jobResp := <-htlcSigJob.resp: case jobResp := <-htlcSigJob.resp:
@ -2780,12 +2785,12 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
// active jobs. // active jobs.
if jobResp.err != nil { if jobResp.err != nil {
close(cancelChan) close(cancelChan)
return nil, nil, err return sig, htlcSigs, err
} }
htlcSigs = append(htlcSigs, jobResp.sig) htlcSigs = append(htlcSigs, jobResp.sig)
case <-lc.quit: case <-lc.quit:
return nil, nil, fmt.Errorf("channel shutting down") return sig, htlcSigs, fmt.Errorf("channel shutting down")
} }
} }
@ -2794,10 +2799,10 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
// can retransmit it if necessary. // can retransmit it if necessary.
commitDiff, err := lc.createCommitDiff(newCommitView, sig, htlcSigs) commitDiff, err := lc.createCommitDiff(newCommitView, sig, htlcSigs)
if err != nil { if err != nil {
return nil, nil, err return sig, htlcSigs, err
} }
if lc.channelState.AppendRemoteCommitChain(commitDiff); err != nil { if lc.channelState.AppendRemoteCommitChain(commitDiff); err != nil {
return nil, nil, err return sig, htlcSigs, err
} }
// TODO(roasbeef): check that one eclair bug // TODO(roasbeef): check that one eclair bug
@ -3128,13 +3133,13 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
// commitment state. The jobs generated are fully populated, and can be sent // commitment state. The jobs generated are fully populated, and can be sent
// directly into the pool of workers. // directly into the pool of workers.
func genHtlcSigValidationJobs(localCommitmentView *commitment, func genHtlcSigValidationJobs(localCommitmentView *commitment,
keyRing *CommitmentKeyRing, htlcSigs []*btcec.Signature, keyRing *CommitmentKeyRing, htlcSigs []lnwire.Sig,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) []verifyJob { localChanCfg, remoteChanCfg *channeldb.ChannelConfig) ([]verifyJob, error) {
// If this new commitment state doesn't have any HTLC's that are to be // If this new commitment state doesn't have any HTLC's that are to be
// signed, then we'll return a nil slice. // signed, then we'll return a nil slice.
if len(htlcSigs) == 0 { if len(htlcSigs) == 0 {
return nil return nil, nil
} }
txHash := localCommitmentView.txn.TxHash() txHash := localCommitmentView.txn.TxHash()
@ -3154,7 +3159,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
// to validate each signature within the worker pool. // to validate each signature within the worker pool.
i := 0 i := 0
for index := range localCommitmentView.txn.TxOut { for index := range localCommitmentView.txn.TxOut {
var sigHash func() ([]byte, error) var (
sigHash func() ([]byte, error)
sig *btcec.Signature
err error
)
outputIndex := int32(index) outputIndex := int32(index)
switch { switch {
@ -3197,7 +3206,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
// With the sighash generated, we'll also store the // With the sighash generated, we'll also store the
// signature so it can be written to disk if this state // signature so it can be written to disk if this state
// is valid. // is valid.
htlc.sig = htlcSigs[i] sig, err = htlcSigs[i].ToSignature()
if err != nil {
return nil, err
}
htlc.sig = sig
// Otherwise, if this is an outgoing HTLC, then we'll need to // Otherwise, if this is an outgoing HTLC, then we'll need to
// generate a timeout transaction so we can verify the // generate a timeout transaction so we can verify the
@ -3239,7 +3252,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
// With the sighash generated, we'll also store the // With the sighash generated, we'll also store the
// signature so it can be written to disk if this state // signature so it can be written to disk if this state
// is valid. // is valid.
htlc.sig = htlcSigs[i] sig, err = htlcSigs[i].ToSignature()
if err != nil {
return nil, err
}
htlc.sig = sig
default: default:
continue continue
@ -3247,14 +3264,14 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
verifyJobs = append(verifyJobs, verifyJob{ verifyJobs = append(verifyJobs, verifyJob{
pubKey: keyRing.RemoteHtlcKey, pubKey: keyRing.RemoteHtlcKey,
sig: htlcSigs[i], sig: sig,
sigHash: sigHash, sigHash: sigHash,
}) })
i++ i++
} }
return verifyJobs return verifyJobs, nil
} }
// InvalidCommitSigError is a struct that implements the error interface to // InvalidCommitSigError is a struct that implements the error interface to
@ -3292,8 +3309,8 @@ var _ error = (*InvalidCommitSigError)(nil)
// to our local commitment chain. Once we send a revocation for our prior // to our local commitment chain. Once we send a revocation for our prior
// state, then this newly added commitment becomes our current accepted channel // state, then this newly added commitment becomes our current accepted channel
// state. // state.
func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature, func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig,
htlcSigs []*btcec.Signature) error { htlcSigs []lnwire.Sig) error {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
@ -3366,8 +3383,14 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
// As an optimization, we'll generate a series of jobs for the worker // As an optimization, we'll generate a series of jobs for the worker
// pool to verify each of the HTLc signatures presented. Once // pool to verify each of the HTLc signatures presented. Once
// generated, we'll submit these jobs to the worker pool. // generated, we'll submit these jobs to the worker pool.
verifyJobs := genHtlcSigValidationJobs(localCommitmentView, verifyJobs, err := genHtlcSigValidationJobs(
keyRing, htlcSigs, lc.localChanCfg, lc.remoteChanCfg) localCommitmentView, keyRing, htlcSigs, lc.localChanCfg,
lc.remoteChanCfg,
)
if err != nil {
return err
}
cancelChan := make(chan struct{}) cancelChan := make(chan struct{})
verifyResps := lc.sigPool.SubmitVerifyBatch(verifyJobs, cancelChan) verifyResps := lc.sigPool.SubmitVerifyBatch(verifyJobs, cancelChan)
@ -3379,7 +3402,11 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
Y: lc.remoteChanCfg.MultiSigKey.Y, Y: lc.remoteChanCfg.MultiSigKey.Y,
Curve: btcec.S256(), Curve: btcec.S256(),
} }
if !commitSig.Verify(sigHash, &verifyKey) { cSig, err := commitSig.ToSignature()
if err != nil {
return err
}
if !cSig.Verify(sigHash, &verifyKey) {
close(cancelChan) close(cancelChan)
// If we fail to validate their commitment signature, we'll // If we fail to validate their commitment signature, we'll
@ -3390,7 +3417,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
localCommitTx.Serialize(&txBytes) localCommitTx.Serialize(&txBytes)
return &InvalidCommitSigError{ return &InvalidCommitSigError{
commitHeight: nextHeight, commitHeight: nextHeight,
commitSig: commitSig.Serialize(), commitSig: commitSig.ToSignatureBytes(),
sigHash: sigHash, sigHash: sigHash,
commitTx: txBytes.Bytes(), commitTx: txBytes.Bytes(),
} }
@ -3414,7 +3441,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
// The signature checks out, so we can now add the new commitment to // The signature checks out, so we can now add the new commitment to
// our local commitment chain. // our local commitment chain.
localCommitmentView.sig = commitSig.Serialize() localCommitmentView.sig = commitSig.ToSignatureBytes()
lc.localCommitChain.addCommitment(localCommitmentView) lc.localCommitChain.addCommitment(localCommitmentView)
// If we are not channel initiator, then the commitment just received // If we are not channel initiator, then the commitment just received

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"io/ioutil" "io/ioutil"
"math/big"
"math/rand" "math/rand"
"os" "os"
"reflect" "reflect"
@ -2768,20 +2767,20 @@ func TestChanSyncOweCommitment(t *testing.T) {
t.Fatalf("expected a CommitSig message, instead have %v", t.Fatalf("expected a CommitSig message, instead have %v",
spew.Sdump(aliceMsgsToSend[4])) spew.Sdump(aliceMsgsToSend[4]))
} }
if !commitSigMsg.CommitSig.IsEqual(aliceSig) { if commitSigMsg.CommitSig != aliceSig {
t.Fatalf("commit sig msgs don't match: expected %x got %x", t.Fatalf("commit sig msgs don't match: expected %x got %x",
aliceSig.Serialize(), commitSigMsg.CommitSig.Serialize()) aliceSig, commitSigMsg.CommitSig)
} }
if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) { if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v", t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(aliceHtlcSigs), len(commitSigMsg.HtlcSigs)) len(aliceHtlcSigs), len(commitSigMsg.HtlcSigs))
} }
for i, htlcSig := range commitSigMsg.HtlcSigs { for i, htlcSig := range commitSigMsg.HtlcSigs {
if !htlcSig.IsEqual(aliceHtlcSigs[i]) { if htlcSig != aliceHtlcSigs[i] {
t.Fatalf("htlc sig msgs don't match: "+ t.Fatalf("htlc sig msgs don't match: "+
"expected %x got %x", "expected %x got %x",
aliceHtlcSigs[i].Serialize(), aliceHtlcSigs[i],
htlcSig.Serialize()) htlcSig)
} }
} }
} }
@ -3228,20 +3227,19 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
t.Fatalf("expected bob to re-send commit sig, instead sending: %v", t.Fatalf("expected bob to re-send commit sig, instead sending: %v",
spew.Sdump(bobMsgsToSend[1])) spew.Sdump(bobMsgsToSend[1]))
} }
if !bobReCommitSigMsg.CommitSig.IsEqual(bobSig) { if bobReCommitSigMsg.CommitSig != bobSig {
t.Fatalf("commit sig msgs don't match: expected %x got %x", t.Fatalf("commit sig msgs don't match: expected %x got %x",
bobSig.Serialize(), bobReCommitSigMsg.CommitSig.Serialize()) bobSig, bobReCommitSigMsg.CommitSig)
} }
if len(bobReCommitSigMsg.HtlcSigs) != len(bobHtlcSigs) { if len(bobReCommitSigMsg.HtlcSigs) != len(bobHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v", t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(bobHtlcSigs), len(bobReCommitSigMsg.HtlcSigs)) len(bobHtlcSigs), len(bobReCommitSigMsg.HtlcSigs))
} }
for i, htlcSig := range bobReCommitSigMsg.HtlcSigs { for i, htlcSig := range bobReCommitSigMsg.HtlcSigs {
if !htlcSig.IsEqual(aliceHtlcSigs[i]) { if htlcSig != aliceHtlcSigs[i] {
t.Fatalf("htlc sig msgs don't match: "+ t.Fatalf("htlc sig msgs don't match: "+
"expected %x got %x", "expected %x got %x",
bobHtlcSigs[i].Serialize(), bobHtlcSigs[i], htlcSig)
htlcSig.Serialize())
} }
} }
} }
@ -3426,21 +3424,20 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
t.Fatalf("revocation msgs don't match: expected %v, got %v", t.Fatalf("revocation msgs don't match: expected %v, got %v",
bobRevocation, bobReRevoke) bobRevocation, bobReRevoke)
} }
if !bobReCommitSigMsg.CommitSig.IsEqual(bobSigMsg.CommitSig) { if bobReCommitSigMsg.CommitSig != bobSigMsg.CommitSig {
t.Fatalf("commit sig msgs don't match: expected %x got %x", t.Fatalf("commit sig msgs don't match: expected %x got %x",
bobSigMsg.CommitSig.Serialize(), bobSigMsg.CommitSig,
bobReCommitSigMsg.CommitSig.Serialize()) bobReCommitSigMsg.CommitSig)
} }
if len(bobReCommitSigMsg.HtlcSigs) != len(bobSigMsg.HtlcSigs) { if len(bobReCommitSigMsg.HtlcSigs) != len(bobSigMsg.HtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v", t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(bobSigMsg.HtlcSigs), len(bobReCommitSigMsg.HtlcSigs)) len(bobSigMsg.HtlcSigs), len(bobReCommitSigMsg.HtlcSigs))
} }
for i, htlcSig := range bobReCommitSigMsg.HtlcSigs { for i, htlcSig := range bobReCommitSigMsg.HtlcSigs {
if htlcSig.IsEqual(bobSigMsg.HtlcSigs[i]) { if htlcSig != bobSigMsg.HtlcSigs[i] {
t.Fatalf("htlc sig msgs don't match: "+ t.Fatalf("htlc sig msgs don't match: "+
"expected %x got %x", "expected %x got %x",
bobSigMsg.HtlcSigs[i].Serialize(), bobSigMsg.HtlcSigs[i], htlcSig)
htlcSig.Serialize())
} }
} }
@ -3598,20 +3595,19 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
t.Fatalf("expected a CommitSig message, instead have %v", t.Fatalf("expected a CommitSig message, instead have %v",
spew.Sdump(aliceMsgsToSend[1])) spew.Sdump(aliceMsgsToSend[1]))
} }
if !commitSigMsg.CommitSig.IsEqual(aliceSig) { if commitSigMsg.CommitSig != aliceSig {
t.Fatalf("commit sig msgs don't match: expected %x got %x", t.Fatalf("commit sig msgs don't match: expected %x got %x",
aliceSig.Serialize(), commitSigMsg.CommitSig.Serialize()) aliceSig, commitSigMsg.CommitSig)
} }
if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) { if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v", t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(aliceHtlcSigs), len(commitSigMsg.HtlcSigs)) len(aliceHtlcSigs), len(commitSigMsg.HtlcSigs))
} }
for i, htlcSig := range commitSigMsg.HtlcSigs { for i, htlcSig := range commitSigMsg.HtlcSigs {
if !htlcSig.IsEqual(aliceHtlcSigs[i]) { if htlcSig != aliceHtlcSigs[i] {
t.Fatalf("htlc sig msgs don't match: "+ t.Fatalf("htlc sig msgs don't match: "+
"expected %x got %x", "expected %x got %x",
aliceHtlcSigs[i].Serialize(), aliceHtlcSigs[i], htlcSig)
htlcSig.Serialize())
} }
} }
@ -4127,7 +4123,7 @@ func TestInvalidCommitSigError(t *testing.T) {
// Before the signature gets to Bob, we'll mutate it, such that the // Before the signature gets to Bob, we'll mutate it, such that the
// signature is now actually invalid. // signature is now actually invalid.
aliceSig.R.Add(aliceSig.R, new(big.Int).SetInt64(1)) aliceSig[0] ^= 88
// Bob should reject this new state, and return the proper error. // Bob should reject this new state, and return the proper error.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs) err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)

@ -5,6 +5,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
) )
@ -90,7 +91,7 @@ type signJobResp struct {
// sig is the generated signature for a particular signJob In the case // sig is the generated signature for a particular signJob In the case
// of an error during signature generation, then this value sent will // of an error during signature generation, then this value sent will
// be nil. // be nil.
sig *btcec.Signature sig lnwire.Sig
// err is the error that occurred when executing the specified // err is the error that occurred when executing the specified
// signature job. In the case that no error occurred, this value will // signature job. In the case that no error occurred, this value will
@ -185,7 +186,7 @@ func (s *sigPool) poolWorker() {
if err != nil { if err != nil {
select { select {
case sigMsg.resp <- signJobResp{ case sigMsg.resp <- signJobResp{
sig: nil, sig: lnwire.Sig{},
err: err, err: err,
}: }:
continue continue
@ -196,7 +197,7 @@ func (s *sigPool) poolWorker() {
} }
} }
sig, err := btcec.ParseSignature(rawSig, btcec.S256()) sig, err := lnwire.NewSigFromRawSignature(rawSig)
select { select {
case sigMsg.resp <- signJobResp{ case sigMsg.resp <- signJobResp{
sig: sig, sig: sig,

@ -1,10 +1,6 @@
package lnwire package lnwire
import ( import "io"
"io"
"github.com/roasbeef/btcd/btcec"
)
// AnnounceSignatures this is a direct message between two endpoints of a // AnnounceSignatures this is a direct message between two endpoints of a
// channel and serves as an opt-in mechanism to allow the announcement of // channel and serves as an opt-in mechanism to allow the announcement of
@ -27,13 +23,13 @@ type AnnounceSignatures struct {
// NodeSignature is the signature which contains the signed announce // NodeSignature is the signature which contains the signed announce
// channel message, by this signature we proof that we possess of the // channel message, by this signature we proof that we possess of the
// node pub key and creating the reference node_key -> bitcoin_key. // node pub key and creating the reference node_key -> bitcoin_key.
NodeSignature *btcec.Signature NodeSignature Sig
// BitcoinSignature is the signature which contains the signed node // BitcoinSignature is the signature which contains the signed node
// public key, by this signature we proof that we possess of the // public key, by this signature we proof that we possess of the
// bitcoin key and and creating the reverse reference bitcoin_key -> // bitcoin key and and creating the reverse reference bitcoin_key ->
// node_key. // node_key.
BitcoinSignature *btcec.Signature BitcoinSignature Sig
} }
// A compile time check to ensure AnnounceSignatures implements the // A compile time check to ensure AnnounceSignatures implements the

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"io" "io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/chaincfg/chainhash"
) )
@ -16,14 +15,14 @@ type ChannelAnnouncement struct {
// references between node's channel and node. Requiring both nodes // references between node's channel and node. Requiring both nodes
// to sign indicates they are both willing to route other payments via // to sign indicates they are both willing to route other payments via
// this node. // this node.
NodeSig1 *btcec.Signature NodeSig1 Sig
NodeSig2 *btcec.Signature NodeSig2 Sig
// This signatures are used by nodes in order to create cross // This signatures are used by nodes in order to create cross
// references between node's channel and node. Requiring the bitcoin // references between node's channel and node. Requiring the bitcoin
// signatures proves they control the channel. // signatures proves they control the channel.
BitcoinSig1 *btcec.Signature BitcoinSig1 Sig
BitcoinSig2 *btcec.Signature BitcoinSig2 Sig
// Features is the feature vector that encodes the features supported // 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 // by the target node. This field can be used to signal the type of the
@ -42,13 +41,13 @@ type ChannelAnnouncement struct {
// The public keys of the two nodes who are operating the channel, such // The public keys of the two nodes who are operating the channel, such
// that is NodeID1 the numerically-lesser than NodeID2 (ascending // that is NodeID1 the numerically-lesser than NodeID2 (ascending
// numerical order). // numerical order).
NodeID1 *btcec.PublicKey NodeID1 [33]byte
NodeID2 *btcec.PublicKey NodeID2 [33]byte
// Public keys which corresponds to the keys which was declared in // Public keys which corresponds to the keys which was declared in
// multisig funding transaction output. // multisig funding transaction output.
BitcoinKey1 *btcec.PublicKey BitcoinKey1 [33]byte
BitcoinKey2 *btcec.PublicKey BitcoinKey2 [33]byte
} }
// A compile time check to ensure ChannelAnnouncement implements the // A compile time check to ensure ChannelAnnouncement implements the

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"io" "io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/chaincfg/chainhash"
) )
@ -32,7 +31,7 @@ const (
type ChannelUpdate struct { type ChannelUpdate struct {
// Signature is used to validate the announced data and prove the // Signature is used to validate the announced data and prove the
// ownership of node id. // ownership of node id.
Signature *btcec.Signature Signature Sig
// ChainHash denotes the target chain that this channel was opened // ChainHash denotes the target chain that this channel was opened
// within. This value should be the genesis hash of the target chain. // within. This value should be the genesis hash of the target chain.

@ -3,7 +3,6 @@ package lnwire
import ( import (
"io" "io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
) )
@ -27,12 +26,12 @@ type ClosingSigned struct {
FeeSatoshis btcutil.Amount FeeSatoshis btcutil.Amount
// Signature is for the proposed channel close transaction. // Signature is for the proposed channel close transaction.
Signature *btcec.Signature Signature Sig
} }
// NewClosingSigned creates a new empty ClosingSigned message. // NewClosingSigned creates a new empty ClosingSigned message.
func NewClosingSigned(cid ChannelID, fs btcutil.Amount, func NewClosingSigned(cid ChannelID, fs btcutil.Amount,
sig *btcec.Signature) *ClosingSigned { sig Sig) *ClosingSigned {
return &ClosingSigned{ return &ClosingSigned{
ChannelID: cid, ChannelID: cid,

@ -1,10 +1,6 @@
package lnwire package lnwire
import ( import "io"
"io"
"github.com/roasbeef/btcd/btcec"
)
// CommitSig is sent by either side to stage any pending HTLC's in the // CommitSig is sent by either side to stage any pending HTLC's in the
// receiver's pending set into a new commitment state. Implicitly, the new // receiver's pending set into a new commitment state. Implicitly, the new
@ -26,7 +22,7 @@ type CommitSig struct {
// If initiating a new commitment state, this signature should ONLY // If initiating a new commitment state, this signature should ONLY
// cover all of the sending party's pending log updates, and the log // cover all of the sending party's pending log updates, and the log
// updates of the remote party that have been ACK'd. // updates of the remote party that have been ACK'd.
CommitSig *btcec.Signature CommitSig Sig
// HtlcSigs is a signature for each relevant HTLC output within the // HtlcSigs is a signature for each relevant HTLC output within the
// created commitment. The order of the signatures is expected to be // created commitment. The order of the signatures is expected to be
@ -35,7 +31,7 @@ type CommitSig struct {
// sender of this message), a signature for a HTLC timeout transaction // sender of this message), a signature for a HTLC timeout transaction
// should be signed, for each incoming HTLC the HTLC timeout // should be signed, for each incoming HTLC the HTLC timeout
// transaction should be signed. // transaction should be signed.
HtlcSigs []*btcec.Signature HtlcSigs []Sig
} }
// NewCommitSig creates a new empty CommitSig message. // NewCommitSig creates a new empty CommitSig message.

@ -3,7 +3,6 @@ package lnwire
import ( import (
"io" "io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
) )
@ -24,7 +23,7 @@ type FundingCreated struct {
// CommitSig is Alice's signature from Bob's version of the commitment // CommitSig is Alice's signature from Bob's version of the commitment
// transaction. // transaction.
CommitSig *btcec.Signature CommitSig Sig
} }
// A compile time check to ensure FundingCreated implements the lnwire.Message // A compile time check to ensure FundingCreated implements the lnwire.Message

@ -1,10 +1,6 @@
package lnwire package lnwire
import ( import "io"
"io"
"github.com/roasbeef/btcd/btcec"
)
// FundingSigned is sent from Bob (the responder) to Alice (the initiator) // FundingSigned is sent from Bob (the responder) to Alice (the initiator)
// after receiving the funding outpoint and her signature for Bob's version of // after receiving the funding outpoint and her signature for Bob's version of
@ -16,7 +12,7 @@ type FundingSigned struct {
// CommitSig is Bob's signature for Alice's version of the commitment // CommitSig is Bob's signature for Alice's version of the commitment
// transaction. // transaction.
CommitSig *btcec.Signature CommitSig Sig
} }
// A compile time check to ensure FundingSigned implements the lnwire.Message // A compile time check to ensure FundingSigned implements the lnwire.Message

@ -146,7 +146,7 @@ func writeElement(w io.Writer, element interface{}) error {
if _, err := w.Write(b[:]); err != nil { if _, err := w.Write(b[:]); err != nil {
return err return err
} }
case []*btcec.Signature: case []Sig:
var b [2]byte var b [2]byte
numSigs := uint16(len(e)) numSigs := uint16(len(e))
binary.BigEndian.PutUint16(b[:], numSigs) binary.BigEndian.PutUint16(b[:], numSigs)
@ -159,18 +159,9 @@ func writeElement(w io.Writer, element interface{}) error {
return err return err
} }
} }
case *btcec.Signature: case Sig:
if e == nil {
return fmt.Errorf("cannot write nil signature")
}
var b [64]byte
err := SerializeSigToWire(&b, e)
if err != nil {
return err
}
// Write buffer // Write buffer
if _, err = w.Write(b[:]); err != nil { if _, err := w.Write(e[:]); err != nil {
return err return err
} }
case PingPayload: case PingPayload:
@ -210,6 +201,10 @@ func writeElement(w io.Writer, element interface{}) error {
return err return err
} }
if _, err := w.Write(e[:]); err != nil {
return err
}
case [33]byte:
if _, err := w.Write(e[:]); err != nil { if _, err := w.Write(e[:]); err != nil {
return err return err
} }
@ -469,16 +464,16 @@ func readElement(r io.Reader, element interface{}) error {
*e = f *e = f
case *[]*btcec.Signature: case *[]Sig:
var l [2]byte var l [2]byte
if _, err := io.ReadFull(r, l[:]); err != nil { if _, err := io.ReadFull(r, l[:]); err != nil {
return err return err
} }
numSigs := binary.BigEndian.Uint16(l[:]) numSigs := binary.BigEndian.Uint16(l[:])
var sigs []*btcec.Signature var sigs []Sig
if numSigs > 0 { if numSigs > 0 {
sigs = make([]*btcec.Signature, numSigs) sigs = make([]Sig, numSigs)
for i := 0; i < int(numSigs); i++ { for i := 0; i < int(numSigs); i++ {
if err := readElement(r, &sigs[i]); err != nil { if err := readElement(r, &sigs[i]); err != nil {
return err return err
@ -488,13 +483,8 @@ func readElement(r io.Reader, element interface{}) error {
*e = sigs *e = sigs
case **btcec.Signature: case *Sig:
var b [64]byte if _, err := io.ReadFull(r, e[:]); err != nil {
if _, err := io.ReadFull(r, b[:]); err != nil {
return err
}
err = DeserializeSigFromWire(e, b)
if err != nil {
return err return err
} }
case *OpaqueReason: case *OpaqueReason:
@ -541,6 +531,10 @@ func readElement(r io.Reader, element interface{}) error {
if _, err := io.ReadFull(r, *e); err != nil { if _, err := io.ReadFull(r, *e); err != nil {
return err return err
} }
case *[33]byte:
if _, err := io.ReadFull(r, e[:]); err != nil {
return err
}
case []byte: case []byte:
if _, err := io.ReadFull(r, e); err != nil { if _, err := io.ReadFull(r, e); err != nil {
return err return err

@ -52,6 +52,19 @@ func randPubKey() (*btcec.PublicKey, error) {
return priv.PubKey(), nil return priv.PubKey(), nil
} }
func randRawKey() ([33]byte, error) {
var n [33]byte
priv, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
return n, err
}
copy(n[:], priv.PubKey().SerializeCompressed())
return n, nil
}
func randRawFeatureVector(r *rand.Rand) *RawFeatureVector { func randRawFeatureVector(r *rand.Rand) *RawFeatureVector {
featureVec := NewRawFeatureVector() featureVec := NewRawFeatureVector()
for i := 0; i < 10000; i++ { for i := 0; i < 10000; i++ {
@ -266,20 +279,30 @@ func TestLightningWireProtocol(t *testing.T) {
} }
req.FundingPoint.Index = uint32(r.Int31()) % math.MaxUint16 req.FundingPoint.Index = uint32(r.Int31()) % math.MaxUint16
req.CommitSig = testSig var err error
req.CommitSig, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
v[0] = reflect.ValueOf(req) v[0] = reflect.ValueOf(req)
}, },
MsgFundingSigned: func(v []reflect.Value, r *rand.Rand) { MsgFundingSigned: func(v []reflect.Value, r *rand.Rand) {
var c [32]byte var c [32]byte
if _, err := r.Read(c[:]); err != nil { _, err := r.Read(c[:])
if err != nil {
t.Fatalf("unable to generate chan id: %v", err) t.Fatalf("unable to generate chan id: %v", err)
return return
} }
req := FundingSigned{ req := FundingSigned{
ChanID: ChannelID(c), ChanID: ChannelID(c),
CommitSig: testSig, }
req.CommitSig, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
} }
v[0] = reflect.ValueOf(req) v[0] = reflect.ValueOf(req)
@ -305,7 +328,12 @@ func TestLightningWireProtocol(t *testing.T) {
MsgClosingSigned: func(v []reflect.Value, r *rand.Rand) { MsgClosingSigned: func(v []reflect.Value, r *rand.Rand) {
req := ClosingSigned{ req := ClosingSigned{
FeeSatoshis: btcutil.Amount(r.Int63()), FeeSatoshis: btcutil.Amount(r.Int63()),
Signature: testSig, }
var err error
req.Signature, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
} }
if _, err := r.Read(req.ChannelID[:]); err != nil { if _, err := r.Read(req.ChannelID[:]); err != nil {
@ -321,17 +349,27 @@ func TestLightningWireProtocol(t *testing.T) {
t.Fatalf("unable to generate chan id: %v", err) t.Fatalf("unable to generate chan id: %v", err)
return return
} }
req.CommitSig = testSig
var err error
req.CommitSig, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
// Only create the slice if there will be any signatures // Only create the slice if there will be any signatures
// in it to prevent false positive test failures due to // in it to prevent false positive test failures due to
// an empty slice versus a nil slice. // an empty slice versus a nil slice.
numSigs := uint16(r.Int31n(1020)) numSigs := uint16(r.Int31n(1020))
if numSigs > 0 { if numSigs > 0 {
req.HtlcSigs = make([]*btcec.Signature, numSigs) req.HtlcSigs = make([]Sig, numSigs)
} }
for i := 0; i < int(numSigs); i++ { for i := 0; i < int(numSigs); i++ {
req.HtlcSigs[i] = testSig req.HtlcSigs[i], err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
} }
v[0] = reflect.ValueOf(*req) v[0] = reflect.ValueOf(*req)
@ -356,32 +394,48 @@ func TestLightningWireProtocol(t *testing.T) {
v[0] = reflect.ValueOf(*req) v[0] = reflect.ValueOf(*req)
}, },
MsgChannelAnnouncement: func(v []reflect.Value, r *rand.Rand) { MsgChannelAnnouncement: func(v []reflect.Value, r *rand.Rand) {
var err error
req := ChannelAnnouncement{ req := ChannelAnnouncement{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())), ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
Features: randRawFeatureVector(r), Features: randRawFeatureVector(r),
} }
req.NodeSig1 = testSig req.NodeSig1, err = NewSigFromSignature(testSig)
req.NodeSig2 = testSig if err != nil {
req.BitcoinSig1 = testSig t.Fatalf("unable to parse sig: %v", err)
req.BitcoinSig2 = testSig return
}
req.NodeSig2, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
req.BitcoinSig1, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
req.BitcoinSig2, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
var err error req.NodeID1, err = randRawKey()
req.NodeID1, err = randPubKey()
if err != nil { if err != nil {
t.Fatalf("unable to generate key: %v", err) t.Fatalf("unable to generate key: %v", err)
return return
} }
req.NodeID2, err = randPubKey() req.NodeID2, err = randRawKey()
if err != nil { if err != nil {
t.Fatalf("unable to generate key: %v", err) t.Fatalf("unable to generate key: %v", err)
return return
} }
req.BitcoinKey1, err = randPubKey() req.BitcoinKey1, err = randRawKey()
if err != nil { if err != nil {
t.Fatalf("unable to generate key: %v", err) t.Fatalf("unable to generate key: %v", err)
return return
} }
req.BitcoinKey2, err = randPubKey() req.BitcoinKey2, err = randRawKey()
if err != nil { if err != nil {
t.Fatalf("unable to generate key: %v", err) t.Fatalf("unable to generate key: %v", err)
return return
@ -400,8 +454,8 @@ func TestLightningWireProtocol(t *testing.T) {
return return
} }
var err error
req := NodeAnnouncement{ req := NodeAnnouncement{
Signature: testSig,
Features: randRawFeatureVector(r), Features: randRawFeatureVector(r),
Timestamp: uint32(r.Int31()), Timestamp: uint32(r.Int31()),
Alias: a, Alias: a,
@ -413,9 +467,13 @@ func TestLightningWireProtocol(t *testing.T) {
// TODO(roasbeef): proper gen rand addrs // TODO(roasbeef): proper gen rand addrs
Addresses: testAddrs, Addresses: testAddrs,
} }
req.Signature, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
var err error req.NodeID, err = randRawKey()
req.NodeID, err = randPubKey()
if err != nil { if err != nil {
t.Fatalf("unable to generate key: %v", err) t.Fatalf("unable to generate key: %v", err)
return return
@ -424,8 +482,8 @@ func TestLightningWireProtocol(t *testing.T) {
v[0] = reflect.ValueOf(req) v[0] = reflect.ValueOf(req)
}, },
MsgChannelUpdate: func(v []reflect.Value, r *rand.Rand) { MsgChannelUpdate: func(v []reflect.Value, r *rand.Rand) {
var err error
req := ChannelUpdate{ req := ChannelUpdate{
Signature: testSig,
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())), ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
Timestamp: uint32(r.Int31()), Timestamp: uint32(r.Int31()),
Flags: ChanUpdateFlag(r.Int31()), Flags: ChanUpdateFlag(r.Int31()),
@ -434,6 +492,12 @@ func TestLightningWireProtocol(t *testing.T) {
BaseFee: uint32(r.Int31()), BaseFee: uint32(r.Int31()),
FeeRate: uint32(r.Int31()), FeeRate: uint32(r.Int31()),
} }
req.Signature, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
if _, err := r.Read(req.ChainHash[:]); err != nil { if _, err := r.Read(req.ChainHash[:]); err != nil {
t.Fatalf("unable to generate chain hash: %v", err) t.Fatalf("unable to generate chain hash: %v", err)
return return
@ -442,11 +506,23 @@ func TestLightningWireProtocol(t *testing.T) {
v[0] = reflect.ValueOf(req) v[0] = reflect.ValueOf(req)
}, },
MsgAnnounceSignatures: func(v []reflect.Value, r *rand.Rand) { MsgAnnounceSignatures: func(v []reflect.Value, r *rand.Rand) {
var err error
req := AnnounceSignatures{ req := AnnounceSignatures{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())), ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
NodeSignature: testSig,
BitcoinSignature: testSig,
} }
req.NodeSignature, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
req.BitcoinSignature, err = NewSigFromSignature(testSig)
if err != nil {
t.Fatalf("unable to parse sig: %v", err)
return
}
if _, err := r.Read(req.ChannelID[:]); err != nil { if _, err := r.Read(req.ChannelID[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err) t.Fatalf("unable to generate chan id: %v", err)
return return

@ -7,8 +7,6 @@ import (
"io" "io"
"net" "net"
"unicode/utf8" "unicode/utf8"
"github.com/roasbeef/btcd/btcec"
) )
var ( var (
@ -50,7 +48,7 @@ func (n NodeAlias) String() string {
// announcement via a signature using the advertised node pubkey. // announcement via a signature using the advertised node pubkey.
type NodeAnnouncement struct { type NodeAnnouncement struct {
// Signature is used to prove the ownership of node id. // Signature is used to prove the ownership of node id.
Signature *btcec.Signature Signature Sig
// Features is the list of protocol features this node supports. // Features is the list of protocol features this node supports.
Features *RawFeatureVector Features *RawFeatureVector
@ -59,7 +57,7 @@ type NodeAnnouncement struct {
Timestamp uint32 Timestamp uint32
// NodeID is a public key which is used as node identification. // NodeID is a public key which is used as node identification.
NodeID *btcec.PublicKey NodeID [33]byte
// RGBColor is used to customize their node's appearance in maps and // RGBColor is used to customize their node's appearance in maps and
// graphs // graphs

@ -11,8 +11,9 @@ var (
testAmount = MilliSatoshi(1) testAmount = MilliSatoshi(1)
testCtlvExpiry = uint32(2) testCtlvExpiry = uint32(2)
testFlags = uint16(2) testFlags = uint16(2)
sig, _ = NewSigFromSignature(testSig)
testChannelUpdate = ChannelUpdate{ testChannelUpdate = ChannelUpdate{
Signature: testSig, Signature: sig,
ShortChannelID: NewShortChanIDFromInt(1), ShortChannelID: NewShortChanIDFromInt(1),
Timestamp: 1, Timestamp: 1,
Flags: 1, Flags: 1,

@ -6,12 +6,16 @@ import (
"github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
) )
// SerializeSigToWire serializes a *Signature to [64]byte in the format // Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized
// specified by the Lightning RFC. // signatures on the wire, instead of DER encoded signatures. This type
func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error { // provides several methods to convert to/from a regular Bitcoin DER encoded
// signature (raw bytes and *btcec.Signature).
type Sig [64]byte
// Serialize the signature with all the checks that entails. // NewSigFromRawSignature returns a Sig from a Bitcoin raw signature encoded in
sig := e.Serialize() // the cannonical DER encoding.
func NewSigFromRawSignature(sig []byte) (Sig, error) {
var b Sig
// Extract lengths of R and S. The DER representation is laid out as // Extract lengths of R and S. The DER representation is laid out as
// 0x30 <length> 0x02 <length r> r 0x02 <length s> s // 0x30 <length> 0x02 <length r> r 0x02 <length s> s
@ -23,14 +27,14 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
sLen := sig[5+rLen] sLen := sig[5+rLen]
// Check to make sure R and S can both fit into their intended buffers. // Check to make sure R and S can both fit into their intended buffers.
// We check S first because these code blocks decrement sLen and // We check S first because these code blocks decrement sLen and rLen
// rLen in the case of a 33-byte 0-padded integer returned from // in the case of a 33-byte 0-padded integer returned from Serialize()
// Serialize() and rLen is used in calculating array indices for // and rLen is used in calculating array indices for S. We can track
// S. We can track this with additional variables, but it's more // this with additional variables, but it's more efficient to just
// efficient to just check S first. // check S first.
if sLen > 32 { if sLen > 32 {
if (sLen > 33) || (sig[6+rLen] != 0x00) { if (sLen > 33) || (sig[6+rLen] != 0x00) {
return fmt.Errorf("S is over 32 bytes long " + return b, fmt.Errorf("S is over 32 bytes long " +
"without padding") "without padding")
} }
sLen-- sLen--
@ -42,7 +46,7 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
// Do the same for R as we did for S // Do the same for R as we did for S
if rLen > 32 { if rLen > 32 {
if (rLen > 33) || (sig[4] != 0x00) { if (rLen > 33) || (sig[4] != 0x00) {
return fmt.Errorf("R is over 32 bytes long " + return b, fmt.Errorf("R is over 32 bytes long " +
"without padding") "without padding")
} }
rLen-- rLen--
@ -50,13 +54,33 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
} else { } else {
copy(b[32-rLen:], sig[4:4+rLen]) copy(b[32-rLen:], sig[4:4+rLen])
} }
return nil
return b, nil
} }
// DeserializeSigFromWire deserializes a *Signature from [64]byte in the format // NewSigFromSignature creates a new signature as used on the wire, from an
// specified by the Lightning RFC. // existing btcec.Signature.
func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error { func NewSigFromSignature(e *btcec.Signature) (Sig, error) {
// Serialize the signature with all the checks that entails.
return NewSigFromRawSignature(e.Serialize())
}
// ToSignature converts the fixed-sized signature to a btcec.Signature objects
// which can be used for signature validation checks.
func (b *Sig) ToSignature() (*btcec.Signature, error) {
// Parse the signature with strict checks.
sigBytes := b.ToSignatureBytes()
sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256())
if err != nil {
return nil, err
}
return sig, nil
}
// ToSignatureBytes serializes the target fixed-sized signature into the raw
// bytes of a DER encoding.
func (b *Sig) ToSignatureBytes() []byte {
// Extract canonically-padded bigint representations from buffer // Extract canonically-padded bigint representations from buffer
r := extractCanonicalPadding(b[0:32]) r := extractCanonicalPadding(b[0:32])
s := extractCanonicalPadding(b[32:64]) s := extractCanonicalPadding(b[32:64])
@ -75,13 +99,7 @@ func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error {
copy(sigBytes[4:], r) // Copy R copy(sigBytes[4:], r) // Copy R
copy(sigBytes[rLen+6:], s) // Copy S copy(sigBytes[rLen+6:], s) // Copy S
// Parse the signature with strict checks. return sigBytes
sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256())
if err != nil {
return err
}
*e = sig
return nil
} }
// extractCanonicalPadding is a utility function to extract the canonical // extractCanonicalPadding is a utility function to extract the canonical

@ -14,16 +14,16 @@ func TestSignatureSerializeDeserialize(t *testing.T) {
// Local-scoped closure to serialize and deserialize a Signature and // Local-scoped closure to serialize and deserialize a Signature and
// check for errors as well as check if the results are correct. // check for errors as well as check if the results are correct.
signatureSerializeDeserialize := func(e btcec.Signature) error { signatureSerializeDeserialize := func(e btcec.Signature) error {
var b [64]byte sig, err := NewSigFromSignature(&e)
err := SerializeSigToWire(&b, &e)
if err != nil { if err != nil {
return err return err
} }
var e2 *btcec.Signature
err = DeserializeSigFromWire(&e2, b) e2, err := sig.ToSignature()
if err != nil { if err != nil {
return err return err
} }
if e.R.Cmp(e2.R) != 0 { if e.R.Cmp(e2.R) != 0 {
return fmt.Errorf("Pre/post-serialize Rs don't match"+ return fmt.Errorf("Pre/post-serialize Rs don't match"+
": %s, %s", e.R, e2.R) ": %s, %s", e.R, e2.R)

25
peer.go

@ -344,7 +344,9 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
// TODO(roasbeef): can add helper method to get policy for // TODO(roasbeef): can add helper method to get policy for
// particular channel. // particular channel.
var selfPolicy *channeldb.ChannelEdgePolicy var selfPolicy *channeldb.ChannelEdgePolicy
if info != nil && info.NodeKey1.IsEqual(p.server.identityPriv.PubKey()) { if info != nil && bytes.Equal(info.NodeKey1Bytes[:],
p.server.identityPriv.PubKey().SerializeCompressed()) {
selfPolicy = p1 selfPolicy = p1
} else { } else {
selfPolicy = p2 selfPolicy = p2
@ -900,8 +902,7 @@ func messageSummary(msg lnwire.Message) string {
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
return fmt.Sprintf("node=%x, update_time=%v", return fmt.Sprintf("node=%x, update_time=%v",
msg.NodeID.SerializeCompressed(), msg.NodeID, time.Unix(int64(msg.Timestamp), 0))
time.Unix(int64(msg.Timestamp), 0))
case *lnwire.Ping: case *lnwire.Ping:
// No summary. // No summary.
@ -957,13 +958,6 @@ func (p *peer) logWireMessage(msg lnwire.Message, read bool) {
} }
case *lnwire.RevokeAndAck: case *lnwire.RevokeAndAck:
m.NextRevocationKey.Curve = nil m.NextRevocationKey.Curve = nil
case *lnwire.NodeAnnouncement:
m.NodeID.Curve = nil
case *lnwire.ChannelAnnouncement:
m.NodeID1.Curve = nil
m.NodeID2.Curve = nil
m.BitcoinKey1.Curve = nil
m.BitcoinKey2.Curve = nil
case *lnwire.AcceptChannel: case *lnwire.AcceptChannel:
m.FundingKey.Curve = nil m.FundingKey.Curve = nil
m.RevocationPoint.Curve = nil m.RevocationPoint.Curve = nil
@ -1774,16 +1768,17 @@ func createGetLastUpdate(router *routing.ChannelRouter,
"channel by ShortChannelID(%v)", chanID) "channel by ShortChannelID(%v)", chanID)
} }
// If we're the outgoing node on the first edge, then that
// means the second edge is our policy. Otherwise, the first
// edge is our policy.
var local *channeldb.ChannelEdgePolicy var local *channeldb.ChannelEdgePolicy
if bytes.Compare(edge1.Node.PubKey.SerializeCompressed(), if bytes.Equal(edge1.Node.PubKeyBytes[:], pubKey[:]) {
pubKey[:]) == 0 {
local = edge2 local = edge2
} else { } else {
local = edge1 local = edge1
} }
update := &lnwire.ChannelUpdate{ update := &lnwire.ChannelUpdate{
Signature: local.Signature,
ChainHash: info.ChainHash, ChainHash: info.ChainHash,
ShortChannelID: lnwire.NewShortChanIDFromInt(local.ChannelID), ShortChannelID: lnwire.NewShortChanIDFromInt(local.ChannelID),
Timestamp: uint32(local.LastUpdate.Unix()), Timestamp: uint32(local.LastUpdate.Unix()),
@ -1793,6 +1788,10 @@ func createGetLastUpdate(router *routing.ChannelRouter,
BaseFee: uint32(local.FeeBaseMSat), BaseFee: uint32(local.FeeBaseMSat),
FeeRate: uint32(local.FeeProportionalMillionths), FeeRate: uint32(local.FeeProportionalMillionths),
} }
update.Signature, err = lnwire.NewSigFromRawSignature(local.SigBytes)
if err != nil {
return nil, err
}
hswcLog.Debugf("Sending latest channel_update: %v", hswcLog.Debugf("Sending latest channel_update: %v",
spew.Sdump(update)) spew.Sdump(update))

@ -14,8 +14,6 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
) )
@ -95,8 +93,7 @@ func TestPeerChannelClosureAcceptFeeResponder(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
initSig := append(initiatorSig, byte(txscript.SigHashAll)) parsedSig, err := lnwire.NewSigFromRawSignature(initiatorSig)
parsedSig, err := btcec.ParseSignature(initSig, btcec.S256())
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }
@ -183,7 +180,7 @@ func TestPeerChannelClosureAcceptFeeInitiator(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to create close proposal: %v", err) t.Fatalf("unable to create close proposal: %v", err)
} }
parsedSig, err := btcec.ParseSignature(closeSig, btcec.S256()) parsedSig, err := lnwire.NewSigFromRawSignature(closeSig)
if err != nil { if err != nil {
t.Fatalf("unable to parse signature: %v", err) t.Fatalf("unable to parse signature: %v", err)
} }
@ -295,7 +292,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
parsedSig, err := btcec.ParseSignature(initiatorSig, btcec.S256()) parsedSig, err := lnwire.NewSigFromRawSignature(initiatorSig)
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }
@ -339,7 +336,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
parsedSig, err = btcec.ParseSignature(initiatorSig, btcec.S256()) parsedSig, err = lnwire.NewSigFromRawSignature(initiatorSig)
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }
@ -384,8 +381,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
initSig := append(initiatorSig, byte(txscript.SigHashAll)) parsedSig, err = lnwire.NewSigFromRawSignature(initiatorSig)
parsedSig, err = btcec.ParseSignature(initSig, btcec.S256())
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }
@ -478,7 +474,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to create close proposal: %v", err) t.Fatalf("unable to create close proposal: %v", err)
} }
parsedSig, err := btcec.ParseSignature(closeSig, btcec.S256()) parsedSig, err := lnwire.NewSigFromRawSignature(closeSig)
if err != nil { if err != nil {
t.Fatalf("unable to parse signature: %v", err) t.Fatalf("unable to parse signature: %v", err)
} }
@ -544,7 +540,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
parsedSig, err = btcec.ParseSignature(responderSig, btcec.S256()) parsedSig, err = lnwire.NewSigFromRawSignature(responderSig)
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }
@ -590,8 +586,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) {
t.Fatalf("error creating close proposal: %v", err) t.Fatalf("error creating close proposal: %v", err)
} }
respSig := append(responderSig, byte(txscript.SigHashAll)) parsedSig, err = lnwire.NewSigFromRawSignature(responderSig)
parsedSig, err = btcec.ParseSignature(respSig, btcec.S256())
if err != nil { if err != nil {
t.Fatalf("error parsing signature: %v", err) t.Fatalf("error parsing signature: %v", err)
} }

@ -239,7 +239,7 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
// With the next candidate path found, we'll attempt to turn this into // With the next candidate path found, we'll attempt to turn this into
// a route by applying the time-lock and fee requirements. // a route by applying the time-lock and fee requirements.
sourceVertex := NewVertex(p.mc.selfNode.PubKey) sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes)
route, err := newRoute(payment.Amount, sourceVertex, path, height, route, err := newRoute(payment.Amount, sourceVertex, path, height,
finalCltvDelta) finalCltvDelta)
if err != nil { if err != nil {

@ -296,9 +296,13 @@ func addToTopologyChange(graph *channeldb.ChannelGraph, update *TopologyChange,
// Any node announcement maps directly to a NetworkNodeUpdate struct. // Any node announcement maps directly to a NetworkNodeUpdate struct.
// No further data munging or db queries are required. // No further data munging or db queries are required.
case *channeldb.LightningNode: case *channeldb.LightningNode:
pubKey, err := m.PubKey()
if err != nil {
return err
}
nodeUpdate := &NetworkNodeUpdate{ nodeUpdate := &NetworkNodeUpdate{
Addresses: m.Addresses, Addresses: m.Addresses,
IdentityKey: m.PubKey, IdentityKey: pubKey,
Alias: m.Alias, Alias: m.Alias,
} }
nodeUpdate.IdentityKey.Curve = nil nodeUpdate.IdentityKey.Curve = nil
@ -332,6 +336,15 @@ func addToTopologyChange(graph *channeldb.ChannelGraph, update *TopologyChange,
connectingNode = edgeInfo.NodeKey1 connectingNode = edgeInfo.NodeKey1
} }
aNode, err := sourceNode()
if err != nil {
return err
}
cNode, err := connectingNode()
if err != nil {
return err
}
edgeUpdate := &ChannelEdgeUpdate{ edgeUpdate := &ChannelEdgeUpdate{
ChanID: m.ChannelID, ChanID: m.ChannelID,
ChanPoint: edgeInfo.ChannelPoint, ChanPoint: edgeInfo.ChannelPoint,
@ -340,8 +353,8 @@ func addToTopologyChange(graph *channeldb.ChannelGraph, update *TopologyChange,
MinHTLC: m.MinHTLC, MinHTLC: m.MinHTLC,
BaseFee: m.FeeBaseMSat, BaseFee: m.FeeBaseMSat,
FeeRate: m.FeeProportionalMillionths, FeeRate: m.FeeProportionalMillionths,
AdvertisingNode: sourceNode, AdvertisingNode: aNode,
ConnectingNode: connectingNode, ConnectingNode: cNode,
} }
edgeUpdate.AdvertisingNode.Curve = nil edgeUpdate.AdvertisingNode.Curve = nil
edgeUpdate.ConnectingNode.Curve = nil edgeUpdate.ConnectingNode.Curve = nil

@ -51,23 +51,25 @@ func createTestNode() (*channeldb.LightningNode, error) {
} }
pub := priv.PubKey().SerializeCompressed() pub := priv.PubKey().SerializeCompressed()
return &channeldb.LightningNode{ n := &channeldb.LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Unix(updateTime, 0), LastUpdate: time.Unix(updateTime, 0),
Addresses: testAddrs, Addresses: testAddrs,
PubKey: priv.PubKey(),
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + string(pub[:]), Alias: "kek" + string(pub[:]),
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
Features: testFeatures, Features: testFeatures,
}, nil }
copy(n.PubKeyBytes[:], pub)
return n, nil
} }
func randEdgePolicy(chanID *lnwire.ShortChannelID, func randEdgePolicy(chanID *lnwire.ShortChannelID,
node *channeldb.LightningNode) *channeldb.ChannelEdgePolicy { node *channeldb.LightningNode) *channeldb.ChannelEdgePolicy {
return &channeldb.ChannelEdgePolicy{ return &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
LastUpdate: time.Unix(int64(prand.Int31()), 0), LastUpdate: time.Unix(int64(prand.Int31()), 0),
TimeLockDelta: uint16(prand.Int63()), TimeLockDelta: uint16(prand.Int63()),
@ -371,18 +373,18 @@ func TestEdgeUpdateNotification(t *testing.T) {
// Finally, to conclude our test set up, we'll create a channel // Finally, to conclude our test set up, we'll create a channel
// update to announce the created channel between the two nodes. // update to announce the created channel between the two nodes.
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: node1.PubKey, NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: node2.PubKey, NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: bitcoinKey1,
BitcoinKey2: bitcoinKey2,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@ -450,8 +452,17 @@ func TestEdgeUpdateNotification(t *testing.T) {
// Create lookup map for notifications we are intending to receive. Entries // Create lookup map for notifications we are intending to receive. Entries
// are removed from the map when the anticipated notification is received. // are removed from the map when the anticipated notification is received.
var waitingFor = map[Vertex]int{ var waitingFor = map[Vertex]int{
NewVertex(node1.PubKey): 1, Vertex(node1.PubKeyBytes): 1,
NewVertex(node2.PubKey): 2, Vertex(node2.PubKeyBytes): 2,
}
node1Pub, err := node1.PubKey()
if err != nil {
t.Fatalf("unable to encode key: %v", err)
}
node2Pub, err := node2.PubKey()
if err != nil {
t.Fatalf("unable to encode key: %v", err)
} }
const numEdgePolicies = 2 const numEdgePolicies = 2
@ -473,20 +484,20 @@ func TestEdgeUpdateNotification(t *testing.T) {
case 1: case 1:
// Received notification corresponding to edge1. // Received notification corresponding to edge1.
assertEdgeCorrect(t, edgeUpdate, edge1) assertEdgeCorrect(t, edgeUpdate, edge1)
if !edgeUpdate.AdvertisingNode.IsEqual(node1.PubKey) { if !edgeUpdate.AdvertisingNode.IsEqual(node1Pub) {
t.Fatal("advertising node mismatch") t.Fatal("advertising node mismatch")
} }
if !edgeUpdate.ConnectingNode.IsEqual(node2.PubKey) { if !edgeUpdate.ConnectingNode.IsEqual(node2Pub) {
t.Fatal("connecting node mismatch") t.Fatal("connecting node mismatch")
} }
case 2: case 2:
// Received notification corresponding to edge2. // Received notification corresponding to edge2.
assertEdgeCorrect(t, edgeUpdate, edge2) assertEdgeCorrect(t, edgeUpdate, edge2)
if !edgeUpdate.AdvertisingNode.IsEqual(node2.PubKey) { if !edgeUpdate.AdvertisingNode.IsEqual(node2Pub) {
t.Fatal("advertising node mismatch") t.Fatal("advertising node mismatch")
} }
if !edgeUpdate.ConnectingNode.IsEqual(node1.PubKey) { if !edgeUpdate.ConnectingNode.IsEqual(node1Pub) {
t.Fatal("connecting node mismatch") t.Fatal("connecting node mismatch")
} }
@ -494,8 +505,8 @@ func TestEdgeUpdateNotification(t *testing.T) {
t.Fatal("invalid edge index") t.Fatal("invalid edge index")
} }
// Remove entry from waitingFor map to ensure we don't double count a // Remove entry from waitingFor map to ensure
// repeat notification. // we don't double count a repeat notification.
delete(waitingFor, nodeVertex) delete(waitingFor, nodeVertex)
} else { } else {
@ -552,18 +563,18 @@ func TestNodeUpdateNotification(t *testing.T) {
} }
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: node1.PubKey, NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: node2.PubKey, NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: bitcoinKey1,
BitcoinKey2: bitcoinKey2,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
// Adding the edge will add the nodes to the graph, but with no info // Adding the edge will add the nodes to the graph, but with no info
// except the pubkey known. // except the pubkey known.
@ -589,15 +600,17 @@ func TestNodeUpdateNotification(t *testing.T) {
assertNodeNtfnCorrect := func(t *testing.T, ann *channeldb.LightningNode, assertNodeNtfnCorrect := func(t *testing.T, ann *channeldb.LightningNode,
nodeUpdate *NetworkNodeUpdate) { nodeUpdate *NetworkNodeUpdate) {
nodeKey, _ := ann.PubKey()
// The notification received should directly map the // The notification received should directly map the
// announcement originally sent. // announcement originally sent.
if nodeUpdate.Addresses[0] != ann.Addresses[0] { if nodeUpdate.Addresses[0] != ann.Addresses[0] {
t.Fatalf("node address doesn't match: expected %v, got %v", t.Fatalf("node address doesn't match: expected %v, got %v",
nodeUpdate.Addresses[0], ann.Addresses[0]) nodeUpdate.Addresses[0], ann.Addresses[0])
} }
if !nodeUpdate.IdentityKey.IsEqual(ann.PubKey) { if !nodeUpdate.IdentityKey.IsEqual(nodeKey) {
t.Fatalf("node identity keys don't match: expected %x, "+ t.Fatalf("node identity keys don't match: expected %x, "+
"got %x", ann.PubKey.SerializeCompressed(), "got %x", nodeKey.SerializeCompressed(),
nodeUpdate.IdentityKey.SerializeCompressed()) nodeUpdate.IdentityKey.SerializeCompressed())
} }
if nodeUpdate.Alias != ann.Alias { if nodeUpdate.Alias != ann.Alias {
@ -609,8 +622,8 @@ func TestNodeUpdateNotification(t *testing.T) {
// Create lookup map for notifications we are intending to receive. Entries // Create lookup map for notifications we are intending to receive. Entries
// are removed from the map when the anticipated notification is received. // are removed from the map when the anticipated notification is received.
var waitingFor = map[Vertex]int{ var waitingFor = map[Vertex]int{
NewVertex(node1.PubKey): 1, Vertex(node1.PubKeyBytes): 1,
NewVertex(node2.PubKey): 2, Vertex(node2.PubKeyBytes): 2,
} }
// Exactly two notifications should be sent, each corresponding to the // Exactly two notifications should be sent, each corresponding to the
@ -738,18 +751,18 @@ func TestNotificationCancellation(t *testing.T) {
ntfnClient.Cancel() ntfnClient.Cancel()
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: node1.PubKey, NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: node2.PubKey, NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: bitcoinKey1,
BitcoinKey2: bitcoinKey2,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@ -819,18 +832,18 @@ func TestChannelCloseNotification(t *testing.T) {
// Finally, to conclude our test set up, we'll create a channel // Finally, to conclude our test set up, we'll create a channel
// announcement to announce the created channel between the two nodes. // announcement to announce the created channel between the two nodes.
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: node1.PubKey, NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: node2.PubKey, NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: bitcoinKey1,
BitcoinKey2: bitcoinKey2,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }

@ -1,6 +1,7 @@
package routing package routing
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math" "math"
@ -148,7 +149,7 @@ type Route struct {
// target node is not found in the route, then false is returned. // target node is not found in the route, then false is returned.
func (r *Route) nextHopVertex(n *btcec.PublicKey) (Vertex, bool) { func (r *Route) nextHopVertex(n *btcec.PublicKey) (Vertex, bool) {
hop, ok := r.nextHopMap[NewVertex(n)] hop, ok := r.nextHopMap[NewVertex(n)]
return NewVertex(hop.Node.PubKey), ok return Vertex(hop.Node.PubKeyBytes), ok
} }
// nextHopChannel returns the uint64 channel ID of the next hop after the // nextHopChannel returns the uint64 channel ID of the next hop after the
@ -259,7 +260,7 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
// First, we'll update both the node and channel index, to // First, we'll update both the node and channel index, to
// indicate that this Vertex, and outgoing channel link are // indicate that this Vertex, and outgoing channel link are
// present within this route. // present within this route.
v := NewVertex(edge.Node.PubKey) v := Vertex(edge.Node.PubKeyBytes)
route.nodeIndex[v] = struct{}{} route.nodeIndex[v] = struct{}{}
route.chanIndex[edge.ChannelID] = struct{}{} route.chanIndex[edge.ChannelID] = struct{}{}
@ -314,7 +315,6 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
AmtToForward: amtToForward, AmtToForward: amtToForward,
Fee: fee, Fee: fee,
} }
edge.Node.PubKey.Curve = nil
route.TotalFees += nextHop.Fee route.TotalFees += nextHop.Fee
@ -361,7 +361,7 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
// We'll then make a second run through our route in order to set up // We'll then make a second run through our route in order to set up
// our prev hop mapping. // our prev hop mapping.
for _, hop := range route.Hops { for _, hop := range route.Hops {
vertex := NewVertex(hop.Channel.Node.PubKey) vertex := Vertex(hop.Channel.Node.PubKeyBytes)
route.prevHopMap[vertex] = hop.Channel route.prevHopMap[vertex] = hop.Channel
} }
@ -393,7 +393,7 @@ func (v Vertex) String() string {
// directional edge with the node's ID in the opposite direction. // directional edge with the node's ID in the opposite direction.
type edgeWithPrev struct { type edgeWithPrev struct {
edge *ChannelHop edge *ChannelHop
prevNode *btcec.PublicKey prevNode [33]byte
} }
// edgeWeight computes the weight of an edge. This value is used when searching // edgeWeight computes the weight of an edge. This value is used when searching
@ -440,7 +440,7 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
if err := graph.ForEachNode(tx, func(_ *bolt.Tx, node *channeldb.LightningNode) error { if err := graph.ForEachNode(tx, func(_ *bolt.Tx, node *channeldb.LightningNode) error {
// TODO(roasbeef): with larger graph can just use disk seeks // TODO(roasbeef): with larger graph can just use disk seeks
// with a visited map // with a visited map
distance[NewVertex(node.PubKey)] = nodeWithDist{ distance[Vertex(node.PubKeyBytes)] = nodeWithDist{
dist: infinity, dist: infinity,
node: node, node: node,
} }
@ -455,7 +455,7 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// To start, we add the source of our path finding attempt to the // To start, we add the source of our path finding attempt to the
// distance map with with a distance of 0. This indicates our starting // distance map with with a distance of 0. This indicates our starting
// point in the graph traversal. // point in the graph traversal.
sourceVertex := NewVertex(sourceNode.PubKey) sourceVertex := Vertex(sourceNode.PubKeyBytes)
distance[sourceVertex] = nodeWithDist{ distance[sourceVertex] = nodeWithDist{
dist: 0, dist: 0,
node: sourceNode, node: sourceNode,
@ -465,6 +465,8 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// heap. // heap.
heap.Push(&nodeHeap, distance[sourceVertex]) heap.Push(&nodeHeap, distance[sourceVertex])
targetBytes := target.SerializeCompressed()
// We'll use this map as a series of "previous" hop pointers. So to get // We'll use this map as a series of "previous" hop pointers. So to get
// to `Vertex` we'll take the edge that it's mapped to within `prev`. // to `Vertex` we'll take the edge that it's mapped to within `prev`.
prev := make(map[Vertex]edgeWithPrev) prev := make(map[Vertex]edgeWithPrev)
@ -477,19 +479,19 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// If we've reached our target (or we don't have any outgoing // If we've reached our target (or we don't have any outgoing
// edges), then we're done here and can exit the graph // edges), then we're done here and can exit the graph
// traversal early. // traversal early.
if bestNode.PubKey.IsEqual(target) { if bytes.Equal(bestNode.PubKeyBytes[:], targetBytes) {
break break
} }
// Now that we've found the next potential step to take we'll // Now that we've found the next potential step to take we'll
// examine all the outgoing edge (channels) from this node to // examine all the outgoing edge (channels) from this node to
// further our graph traversal. // further our graph traversal.
pivot := NewVertex(bestNode.PubKey) pivot := Vertex(bestNode.PubKeyBytes)
err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx, err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx,
edgeInfo *channeldb.ChannelEdgeInfo, edgeInfo *channeldb.ChannelEdgeInfo,
outEdge, inEdge *channeldb.ChannelEdgePolicy) error { outEdge, inEdge *channeldb.ChannelEdgePolicy) error {
v := NewVertex(outEdge.Node.PubKey) v := Vertex(outEdge.Node.PubKeyBytes)
// If the outgoing edge is currently disabled, then // If the outgoing edge is currently disabled, then
// we'll stop here, as we shouldn't attempt to route // we'll stop here, as we shouldn't attempt to route
@ -538,7 +540,7 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
ChannelEdgePolicy: outEdge, ChannelEdgePolicy: outEdge,
Capacity: edgeInfo.Capacity, Capacity: edgeInfo.Capacity,
}, },
prevNode: bestNode.PubKey, prevNode: bestNode.PubKeyBytes,
} }
// Add this new node to our heap as we'd like // Add this new node to our heap as we'd like
@ -573,9 +575,8 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// backwards from this hop via the prev pointer for this hop // backwards from this hop via the prev pointer for this hop
// within the prevHop map. // within the prevHop map.
pathEdges = append(pathEdges, prev[prevNode].edge) pathEdges = append(pathEdges, prev[prevNode].edge)
prev[prevNode].edge.Node.PubKey.Curve = nil
prevNode = NewVertex(prev[prevNode].prevNode) prevNode = Vertex(prev[prevNode].prevNode)
} }
// The route is invalid if it spans more than 20 hops. The current // The route is invalid if it spans more than 20 hops. The current
@ -648,8 +649,6 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph,
shortestPaths = append(shortestPaths, firstPath) shortestPaths = append(shortestPaths, firstPath)
source.PubKey.Curve = nil
// While we still have candidate paths to explore we'll keep exploring // While we still have candidate paths to explore we'll keep exploring
// the sub-graphs created to find the next k-th shortest path. // the sub-graphs created to find the next k-th shortest path.
for k := 1; k < 100; k++ { for k := 1; k < 100; k++ {
@ -688,12 +687,12 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// Next we'll remove all entries in the root path that // Next we'll remove all entries in the root path that
// aren't the current spur node from the graph. // aren't the current spur node from the graph.
for _, hop := range rootPath { for _, hop := range rootPath {
node := hop.Node.PubKey node := hop.Node.PubKeyBytes
if node.IsEqual(spurNode.PubKey) { if node == spurNode.PubKeyBytes {
continue continue
} }
ignoredVertexes[NewVertex(node)] = struct{}{} ignoredVertexes[Vertex(node)] = struct{}{}
} }
// With the edges that are part of our root path, and // With the edges that are part of our root path, and

@ -53,10 +53,10 @@ var (
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
testAuthProof = channeldb.ChannelAuthProof{ testAuthProof = channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
} }
) )
@ -165,20 +165,16 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
pub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
if err != nil {
return nil, nil, nil, err
}
dbNode := &channeldb.LightningNode{ dbNode := &channeldb.LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Now(), LastUpdate: time.Now(),
Addresses: testAddrs, Addresses: testAddrs,
PubKey: pub,
Alias: node.Alias, Alias: node.Alias,
Features: testFeatures, Features: testFeatures,
} }
copy(dbNode.PubKeyBytes[:], pubBytes)
// We require all aliases within the graph to be unique for our // We require all aliases within the graph to be unique for our
// tests. // tests.
@ -187,6 +183,11 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
"must be unique!") "must be unique!")
} }
pub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
if err != nil {
return nil, nil, nil, err
}
// If the alias is unique, then add the node to the // If the alias is unique, then add the node to the
// alias map for easy lookup. // alias map for easy lookup.
aliasMap[node.Alias] = pub aliasMap[node.Alias] = pub
@ -228,19 +229,11 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
node1Pub, err := btcec.ParsePubKey(node1Bytes, btcec.S256())
if err != nil {
return nil, nil, nil, err
}
node2Bytes, err := hex.DecodeString(edge.Node2) node2Bytes, err := hex.DecodeString(edge.Node2)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
node2Pub, err := btcec.ParsePubKey(node2Bytes, btcec.S256())
if err != nil {
return nil, nil, nil, err
}
fundingTXID := strings.Split(edge.ChannelPoint, ":")[0] fundingTXID := strings.Split(edge.ChannelPoint, ":")[0]
txidBytes, err := chainhash.NewHashFromStr(fundingTXID) txidBytes, err := chainhash.NewHashFromStr(fundingTXID)
@ -256,21 +249,23 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
// nodes. // nodes.
edgeInfo := channeldb.ChannelEdgeInfo{ edgeInfo := channeldb.ChannelEdgeInfo{
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
NodeKey1: node1Pub,
NodeKey2: node2Pub,
BitcoinKey1: node1Pub,
BitcoinKey2: node2Pub,
AuthProof: &testAuthProof, AuthProof: &testAuthProof,
ChannelPoint: fundingPoint, ChannelPoint: fundingPoint,
Capacity: btcutil.Amount(edge.Capacity), Capacity: btcutil.Amount(edge.Capacity),
} }
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes)
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes)
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes)
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
err = graph.AddChannelEdge(&edgeInfo) err = graph.AddChannelEdge(&edgeInfo)
if err != nil && err != channeldb.ErrEdgeAlreadyExist { if err != nil && err != channeldb.ErrEdgeAlreadyExist {
return nil, nil, nil, err return nil, nil, nil, err
} }
edgePolicy := &channeldb.ChannelEdgePolicy{ edgePolicy := &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
Flags: lnwire.ChanUpdateFlag(edge.Flags), Flags: lnwire.ChanUpdateFlag(edge.Flags),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
LastUpdate: time.Now(), LastUpdate: time.Now(),
@ -300,7 +295,7 @@ func TestBasicGraphPathFinding(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
sourceVertex := NewVertex(sourceNode.PubKey) sourceVertex := Vertex(sourceNode.PubKeyBytes)
ignoredEdges := make(map[uint64]struct{}) ignoredEdges := make(map[uint64]struct{})
ignoredVertexes := make(map[Vertex]struct{}) ignoredVertexes := make(map[Vertex]struct{})
@ -342,13 +337,17 @@ func TestBasicGraphPathFinding(t *testing.T) {
} }
// The first hop in the path should be an edge from roasbeef to goku. // The first hop in the path should be an edge from roasbeef to goku.
if !route.Hops[0].Channel.Node.PubKey.IsEqual(aliases["songoku"]) { if !bytes.Equal(route.Hops[0].Channel.Node.PubKeyBytes[:],
aliases["songoku"].SerializeCompressed()) {
t.Fatalf("first hop should be goku, is instead: %v", t.Fatalf("first hop should be goku, is instead: %v",
route.Hops[0].Channel.Node.Alias) route.Hops[0].Channel.Node.Alias)
} }
// The second hop should be from goku to sophon. // The second hop should be from goku to sophon.
if !route.Hops[1].Channel.Node.PubKey.IsEqual(aliases["sophon"]) { if !bytes.Equal(route.Hops[1].Channel.Node.PubKeyBytes[:],
aliases["sophon"].SerializeCompressed()) {
t.Fatalf("second hop should be sophon, is instead: %v", t.Fatalf("second hop should be sophon, is instead: %v",
route.Hops[0].Channel.Node.Alias) route.Hops[0].Channel.Node.Alias)
} }
@ -833,7 +832,7 @@ func TestPathFindSpecExample(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to retrieve source node: %v", err) t.Fatalf("unable to retrieve source node: %v", err)
} }
if !source.PubKey.IsEqual(alice) { if !bytes.Equal(source.PubKeyBytes[:], alice.SerializeCompressed()) {
t.Fatalf("source node not set") t.Fatalf("source node not set")
} }

@ -130,7 +130,7 @@ type Config struct {
// forward a fully encoded payment to the first hop in the route // forward a fully encoded payment to the first hop in the route
// denoted by its public key. A non-nil error is to be returned if the // denoted by its public key. A non-nil error is to be returned if the
// payment was unsuccessful. // payment was unsuccessful.
SendToSwitch func(firstHop *btcec.PublicKey, htlcAdd *lnwire.UpdateAddHTLC, SendToSwitch func(firstHop [33]byte, htlcAdd *lnwire.UpdateAddHTLC,
circuit *sphinx.Circuit) ([sha256.Size]byte, error) circuit *sphinx.Circuit) ([sha256.Size]byte, error)
// ChannelPruneExpiry is the duration used to determine if a channel // ChannelPruneExpiry is the duration used to determine if a channel
@ -237,6 +237,9 @@ type ChannelRouter struct {
// consistency between the various database accesses. // consistency between the various database accesses.
channelEdgeMtx *multimutex.Mutex channelEdgeMtx *multimutex.Mutex
rejectMtx sync.RWMutex
rejectCache map[uint64]struct{}
sync.RWMutex sync.RWMutex
quit chan struct{} quit chan struct{}
@ -268,6 +271,7 @@ func New(cfg Config) (*ChannelRouter, error) {
channelEdgeMtx: multimutex.NewMutex(), channelEdgeMtx: multimutex.NewMutex(),
selfNode: selfNode, selfNode: selfNode,
routeCache: make(map[routeTuple][]*Route), routeCache: make(map[routeTuple][]*Route),
rejectCache: make(map[uint64]struct{}),
quit: make(chan struct{}), quit: make(chan struct{}),
}, nil }, nil
} }
@ -504,6 +508,93 @@ func (r *ChannelRouter) syncGraphWithChain() error {
return nil return nil
} }
// pruneZombieChans is a method that will be called periodically to prune out
// any "zombie" channels. We consider channels zombies if *both* edges haven't
// been updated since our zombie horizon. We do this periodically to keep a
// health, lively routing table.
func (r *ChannelRouter) pruneZombieChans() error {
var chansToPrune []wire.OutPoint
chanExpiry := r.cfg.ChannelPruneExpiry
log.Infof("Examining Channel Graph for zombie channels")
// First, we'll collect all the channels which are eligible for garbage
// collection due to being zombies.
filterPruneChans := func(info *channeldb.ChannelEdgeInfo,
e1, e2 *channeldb.ChannelEdgePolicy) error {
// We'll ensure that we don't attempt to prune our *own*
// channels from the graph, as in any case this should be
// re-advertised by the sub-system above us.
if info.NodeKey1Bytes == r.selfNode.PubKeyBytes ||
info.NodeKey2Bytes == r.selfNode.PubKeyBytes {
return nil
}
// If *both* edges haven't been updated for a period of
// chanExpiry, then we'll mark the channel itself as eligible
// for graph pruning.
e1Zombie, e2Zombie := true, true
if e1 != nil {
e1Zombie = time.Since(e1.LastUpdate) >= chanExpiry
if e1Zombie {
log.Tracef("Edge #1 of ChannelPoint(%v) "+
"last update: %v",
info.ChannelPoint, e1.LastUpdate)
}
}
if e2 != nil {
e2Zombie = time.Since(e2.LastUpdate) >= chanExpiry
if e2Zombie {
log.Tracef("Edge #2 of ChannelPoint(%v) "+
"last update: %v",
info.ChannelPoint, e2.LastUpdate)
}
}
if e1Zombie && e2Zombie {
log.Debugf("ChannelPoint(%v) is a zombie, collecting "+
"to prune", info.ChannelPoint)
// TODO(roasbeef): add ability to delete single
// directional edge
chansToPrune = append(chansToPrune, info.ChannelPoint)
// As we're detecting this as a zombie channel, we'll
// add this to the set of recently rejected items so we
// don't re-accept it shortly after.
r.rejectCache[info.ChannelID] = struct{}{}
}
return nil
}
r.rejectMtx.Lock()
defer r.rejectMtx.Unlock()
err := r.cfg.Graph.ForEachChannel(filterPruneChans)
if err != nil {
return fmt.Errorf("Unable to filter local zombie "+
"chans: %v", err)
}
log.Infof("Pruning %v Zombie Channels", len(chansToPrune))
// With the set zombie-like channels obtained, we'll do another pass to
// delete al zombie channels from the channel graph.
for _, chanToPrune := range chansToPrune {
log.Tracef("Pruning zombie chan ChannelPoint(%v)", chanToPrune)
err := r.cfg.Graph.DeleteChannelEdge(&chanToPrune)
if err != nil {
return fmt.Errorf("Unable to prune zombie "+
"chans: %v", err)
}
}
return nil
}
// networkHandler is the primary goroutine for the ChannelRouter. The roles of // networkHandler is the primary goroutine for the ChannelRouter. The roles of
// this goroutine include answering queries related to the state of the // this goroutine include answering queries related to the state of the
// network, pruning the graph on new block notification, applying network // network, pruning the graph on new block notification, applying network
@ -716,79 +807,8 @@ func (r *ChannelRouter) networkHandler() {
// state of the known graph to filter out any zombie channels // state of the known graph to filter out any zombie channels
// for pruning. // for pruning.
case <-graphPruneTicker.C: case <-graphPruneTicker.C:
if err := r.pruneZombieChans(); err != nil {
var chansToPrune []wire.OutPoint log.Errorf("unable to prune zombies: %v", err)
chanExpiry := r.cfg.ChannelPruneExpiry
log.Infof("Examining Channel Graph for zombie channels")
// First, we'll collect all the channels which are
// eligible for garbage collection due to being
// zombies.
filterPruneChans := func(info *channeldb.ChannelEdgeInfo,
e1, e2 *channeldb.ChannelEdgePolicy) error {
// We'll ensure that we don't attempt to prune
// our *own* channels from the graph, as in any
// case this should be re-advertised by the
// sub-system above us.
if info.NodeKey1.IsEqual(r.selfNode.PubKey) ||
info.NodeKey2.IsEqual(r.selfNode.PubKey) {
return nil
}
// If *both* edges haven't been updated for a
// period of chanExpiry, then we'll mark the
// channel itself as eligible for graph
// pruning.
e1Zombie, e2Zombie := true, true
if e1 != nil {
e1Zombie = time.Since(e1.LastUpdate) >= chanExpiry
log.Tracef("Edge #1 of ChannelPoint(%v) "+
"last update: %v",
info.ChannelPoint, e1.LastUpdate)
}
if e2 != nil {
e2Zombie = time.Since(e2.LastUpdate) >= chanExpiry
log.Tracef("Edge #2 of ChannelPoint(%v) "+
"last update: %v",
info.ChannelPoint, e2.LastUpdate)
}
if e1Zombie && e2Zombie {
log.Infof("ChannelPoint(%v) is a "+
"zombie, collecting to prune",
info.ChannelPoint)
// TODO(roasbeef): add ability to
// delete single directional edge
chansToPrune = append(chansToPrune,
info.ChannelPoint)
}
return nil
}
err := r.cfg.Graph.ForEachChannel(filterPruneChans)
if err != nil {
log.Errorf("Unable to local zombie chans: %v", err)
continue
}
log.Infof("Pruning %v Zombie Channels", len(chansToPrune))
// With the set zombie-like channels obtained, we'll do
// another pass to delete al zombie channels from the
// channel graph.
for _, chanToPrune := range chansToPrune {
log.Tracef("Pruning zombie chan ChannelPoint(%v)",
chanToPrune)
err := r.cfg.Graph.DeleteChannelEdge(&chanToPrune)
if err != nil {
log.Errorf("Unable to prune zombie "+
"chans: %v", err)
continue
}
} }
// The router has been signalled to exit, to we exit our main // The router has been signalled to exit, to we exit our main
@ -814,7 +834,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// attack by node announcements, we will ignore such nodes. If // attack by node announcements, we will ignore such nodes. If
// we do know about this node, check that this update brings // we do know about this node, check that this update brings
// info newer than what we already have. // info newer than what we already have.
lastUpdate, exists, err := r.cfg.Graph.HasLightningNode(msg.PubKey) lastUpdate, exists, err := r.cfg.Graph.HasLightningNode(msg.PubKeyBytes)
if err != nil { if err != nil {
return errors.Errorf("unable to query for the "+ return errors.Errorf("unable to query for the "+
"existence of node: %v", err) "existence of node: %v", err)
@ -822,7 +842,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
if !exists { if !exists {
return newErrf(ErrIgnored, "Ignoring node announcement"+ return newErrf(ErrIgnored, "Ignoring node announcement"+
" for node not found in channel graph (%x)", " for node not found in channel graph (%x)",
msg.PubKey.SerializeCompressed()) msg.PubKeyBytes)
} }
// If we've reached this point then we're aware of the vertex // If we've reached this point then we're aware of the vertex
@ -833,18 +853,27 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
lastUpdate.Equal(msg.LastUpdate) { lastUpdate.Equal(msg.LastUpdate) {
return newErrf(ErrOutdated, "Ignoring outdated "+ return newErrf(ErrOutdated, "Ignoring outdated "+
"announcement for %x", msg.PubKey.SerializeCompressed()) "announcement for %x", msg.PubKeyBytes)
} }
if err := r.cfg.Graph.AddLightningNode(msg); err != nil { if err := r.cfg.Graph.AddLightningNode(msg); err != nil {
return errors.Errorf("unable to add node %v to the "+ return errors.Errorf("unable to add node %v to the "+
"graph: %v", msg.PubKey.SerializeCompressed(), err) "graph: %v", msg.PubKeyBytes, err)
} }
log.Infof("Updated vertex data for node=%x", log.Infof("Updated vertex data for node=%x", msg.PubKeyBytes)
msg.PubKey.SerializeCompressed())
case *channeldb.ChannelEdgeInfo: case *channeldb.ChannelEdgeInfo:
// If we recently rejected this channel edge, then we won't
// attempt to re-process it.
r.rejectMtx.RLock()
if _, ok := r.rejectCache[msg.ChannelID]; ok {
r.rejectMtx.RUnlock()
return newErrf(ErrIgnored, "recently rejected "+
"chan_id=%v", msg.ChannelID)
}
r.rejectMtx.RUnlock()
// Prior to processing the announcement we first check if we // Prior to processing the announcement we first check if we
// already know of this channel, if so, then we can exit early. // already know of this channel, if so, then we can exit early.
_, _, exists, err := r.cfg.Graph.HasChannelEdge(msg.ChannelID) _, _, exists, err := r.cfg.Graph.HasChannelEdge(msg.ChannelID)
@ -859,30 +888,28 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// Query the database for the existence of the two nodes in this // Query the database for the existence of the two nodes in this
// channel. If not found, add a partial node to the database, // channel. If not found, add a partial node to the database,
// containing only the node keys. // containing only the node keys.
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey1) _, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey1Bytes)
if !exists { if !exists {
node1 := &channeldb.LightningNode{ node1 := &channeldb.LightningNode{
PubKey: msg.NodeKey1, PubKeyBytes: msg.NodeKey1Bytes,
HaveNodeAnnouncement: false, HaveNodeAnnouncement: false,
} }
err := r.cfg.Graph.AddLightningNode(node1) err := r.cfg.Graph.AddLightningNode(node1)
if err != nil { if err != nil {
return errors.Errorf("unable to add node %v to"+ return errors.Errorf("unable to add node %v to"+
" the graph: %v", " the graph: %v", node1.PubKeyBytes, err)
node1.PubKey.SerializeCompressed(), err)
} }
} }
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey2) _, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey2Bytes)
if !exists { if !exists {
node2 := &channeldb.LightningNode{ node2 := &channeldb.LightningNode{
PubKey: msg.NodeKey2, PubKeyBytes: msg.NodeKey2Bytes,
HaveNodeAnnouncement: false, HaveNodeAnnouncement: false,
} }
err := r.cfg.Graph.AddLightningNode(node2) err := r.cfg.Graph.AddLightningNode(node2)
if err != nil { if err != nil {
return errors.Errorf("unable to add node %v to"+ return errors.Errorf("unable to add node %v to"+
" the graph: %v", " the graph: %v", node2.PubKeyBytes, err)
node2.PubKey.SerializeCompressed(), err)
} }
} }
@ -911,8 +938,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// edge bitcoin keys and channel value corresponds to the // edge bitcoin keys and channel value corresponds to the
// reality. // reality.
_, witnessOutput, err := lnwallet.GenFundingPkScript( _, witnessOutput, err := lnwallet.GenFundingPkScript(
msg.BitcoinKey1.SerializeCompressed(), msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
msg.BitcoinKey2.SerializeCompressed(),
chanUtxo.Value, chanUtxo.Value,
) )
if err != nil { if err != nil {
@ -942,8 +968,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
log.Infof("New channel discovered! Link "+ log.Infof("New channel discovered! Link "+
"connects %x and %x with ChannelPoint(%v): "+ "connects %x and %x with ChannelPoint(%v): "+
"chan_id=%v, capacity=%v", "chan_id=%v, capacity=%v",
msg.NodeKey1.SerializeCompressed(), msg.NodeKey1Bytes, msg.NodeKey2Bytes,
msg.NodeKey2.SerializeCompressed(),
fundingPoint, msg.ChannelID, msg.Capacity) fundingPoint, msg.ChannelID, msg.Capacity)
// As a new edge has been added to the channel graph, we'll // As a new edge has been added to the channel graph, we'll
@ -960,6 +985,16 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
} }
case *channeldb.ChannelEdgePolicy: case *channeldb.ChannelEdgePolicy:
// If we recently rejected this channel edge, then we won't
// attempt to re-process it.
r.rejectMtx.RLock()
if _, ok := r.rejectCache[msg.ChannelID]; ok {
r.rejectMtx.RUnlock()
return newErrf(ErrIgnored, "recently rejected "+
"chan_id=%v", msg.ChannelID)
}
r.rejectMtx.RUnlock()
channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID) channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
// We make sure to hold the mutex for this channel ID, // We make sure to hold the mutex for this channel ID,
@ -1183,7 +1218,8 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
// We can short circuit the routing by opportunistically checking to // We can short circuit the routing by opportunistically checking to
// see if the target vertex event exists in the current graph. // see if the target vertex event exists in the current graph.
if _, exists, err := r.cfg.Graph.HasLightningNode(target); err != nil { targetVertex := NewVertex(target)
if _, exists, err := r.cfg.Graph.HasLightningNode(targetVertex); err != nil {
return nil, err return nil, err
} else if !exists { } else if !exists {
log.Debugf("Target %x is not in known graph", dest) log.Debugf("Target %x is not in known graph", dest)
@ -1221,7 +1257,7 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
// aren't able to support the total satoshis flow once fees have been // aren't able to support the total satoshis flow once fees have been
// factored in. // factored in.
validRoutes := make([]*Route, 0, len(shortestPaths)) validRoutes := make([]*Route, 0, len(shortestPaths))
sourceVertex := NewVertex(r.selfNode.PubKey) sourceVertex := Vertex(r.selfNode.PubKeyBytes)
for _, path := range shortestPaths { for _, path := range shortestPaths {
// Attempt to make the path into a route. We snip off the first // Attempt to make the path into a route. We snip off the first
// hop in the path as it contains a "self-hop" that is inserted // hop in the path as it contains a "self-hop" that is inserted
@ -1289,10 +1325,14 @@ func generateSphinxPacket(route *Route, paymentHash []byte) ([]byte,
// We create a new instance of the public key to avoid possibly // We create a new instance of the public key to avoid possibly
// mutating the curve parameters, which are unset in a higher // mutating the curve parameters, which are unset in a higher
// level in order to avoid spamming the logs. // level in order to avoid spamming the logs.
nodePub, err := hop.Channel.Node.PubKey()
if err != nil {
return nil, nil, err
}
pub := btcec.PublicKey{ pub := btcec.PublicKey{
Curve: btcec.S256(), Curve: btcec.S256(),
X: hop.Channel.Node.PubKey.X, X: nodePub.X,
Y: hop.Channel.Node.PubKey.Y, Y: nodePub.Y,
} }
nodes[i] = &pub nodes[i] = &pub
} }
@ -1453,7 +1493,7 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route
// Attempt to send this payment through the network to complete // Attempt to send this payment through the network to complete
// the payment. If this attempt fails, then we'll continue on // the payment. If this attempt fails, then we'll continue on
// to the next available route. // to the next available route.
firstHop := route.Hops[0].Channel.Node.PubKey firstHop := route.Hops[0].Channel.Node.PubKeyBytes
preImage, sendError = r.cfg.SendToSwitch(firstHop, htlcAdd, preImage, sendError = r.cfg.SendToSwitch(firstHop, htlcAdd,
circuit) circuit)
if sendError != nil { if sendError != nil {
@ -1693,7 +1733,7 @@ func (r *ChannelRouter) applyChannelUpdate(msg *lnwire.ChannelUpdate) error {
} }
err := r.UpdateEdge(&channeldb.ChannelEdgePolicy{ err := r.UpdateEdge(&channeldb.ChannelEdgePolicy{
Signature: msg.Signature, SigBytes: msg.Signature.ToSignatureBytes(),
ChannelID: msg.ShortChannelID.ToUint64(), ChannelID: msg.ShortChannelID.ToUint64(),
LastUpdate: time.Unix(int64(msg.Timestamp), 0), LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Flags: msg.Flags, Flags: msg.Flags,

@ -42,7 +42,7 @@ func (c *testCtx) RestartRouter() error {
Graph: c.graph, Graph: c.graph,
Chain: c.chain, Chain: c.chain,
ChainView: c.chainView, ChainView: c.chainView,
SendToSwitch: func(_ *btcec.PublicKey, SendToSwitch: func(_ [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil return [32]byte{}, nil
}, },
@ -117,8 +117,9 @@ func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func()
Graph: graph, Graph: graph,
Chain: chain, Chain: chain,
ChainView: chainView, ChainView: chainView,
SendToSwitch: func(_ *btcec.PublicKey, SendToSwitch: func(_ [33]byte, _ *lnwire.UpdateAddHTLC,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil return [32]byte{}, nil
}, },
ChannelPruneExpiry: time.Hour * 24, ChannelPruneExpiry: time.Hour * 24,
@ -230,12 +231,16 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
// router's configuration to ignore the path that has luo ji as the // router's configuration to ignore the path that has luo ji as the
// first hop. This should force the router to instead take the // first hop. This should force the router to instead take the
// available two hop path (through satoshi). // available two hop path (through satoshi).
ctx.router.cfg.SendToSwitch = func(n *btcec.PublicKey, ctx.router.cfg.SendToSwitch = func(n [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if ctx.aliases["luoji"].IsEqual(n) { if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
pub, err := sourceNode.PubKey()
if err != nil {
return preImage, err
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey, ErrorSource: pub,
// TODO(roasbeef): temp node failure should be? // TODO(roasbeef): temp node failure should be?
FailureMessage: &lnwire.FailTemporaryChannelFailure{}, FailureMessage: &lnwire.FailTemporaryChannelFailure{},
} }
@ -301,21 +306,26 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
sourcePub, err := sourceNode.PubKey()
if err != nil {
t.Fatalf("unable to fetch source node pub: %v", err)
}
// First, we'll modify the SendToSwitch method to return an error // First, we'll modify the SendToSwitch method to return an error
// indicating that the channel from roasbeef to luoji is not operable // indicating that the channel from roasbeef to luoji is not operable
// with an UnknownNextPeer. // with an UnknownNextPeer.
// //
// TODO(roasbeef): filtering should be intelligent enough so just not // TODO(roasbeef): filtering should be intelligent enough so just not
// go through satoshi at all at this point. // go through satoshi at all at this point.
ctx.router.cfg.SendToSwitch = func(n *btcec.PublicKey, ctx.router.cfg.SendToSwitch = func(n [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if ctx.aliases["luoji"].IsEqual(n) { if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
// We'll first simulate an error from the first // We'll first simulate an error from the first
// outgoing link to simulate the channel from luo ji to // outgoing link to simulate the channel from luo ji to
// roasbeef not having enough capacity. // roasbeef not having enough capacity.
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey, ErrorSource: sourcePub,
FailureMessage: &lnwire.FailTemporaryChannelFailure{}, FailureMessage: &lnwire.FailTemporaryChannelFailure{},
} }
} }
@ -323,7 +333,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Next, we'll create an error from satoshi to indicate // Next, we'll create an error from satoshi to indicate
// that the luoji node is not longer online, which should // that the luoji node is not longer online, which should
// prune out the rest of the routes. // prune out the rest of the routes.
if ctx.aliases["satoshi"].IsEqual(n) { if bytes.Equal(ctx.aliases["satoshi"].SerializeCompressed(), n[:]) {
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: ctx.aliases["satoshi"], ErrorSource: ctx.aliases["satoshi"],
FailureMessage: &lnwire.FailUnknownNextPeer{}, FailureMessage: &lnwire.FailUnknownNextPeer{},
@ -353,12 +363,12 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Next, we'll modify the SendToSwitch method to indicate that luo ji // Next, we'll modify the SendToSwitch method to indicate that luo ji
// wasn't originally online. This should also halt the send all // wasn't originally online. This should also halt the send all
// together as all paths contain luoji and he can't be reached. // together as all paths contain luoji and he can't be reached.
ctx.router.cfg.SendToSwitch = func(n *btcec.PublicKey, ctx.router.cfg.SendToSwitch = func(n [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if ctx.aliases["luoji"].IsEqual(n) { if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey, ErrorSource: sourcePub,
FailureMessage: &lnwire.FailUnknownNextPeer{}, FailureMessage: &lnwire.FailUnknownNextPeer{},
} }
} }
@ -380,14 +390,14 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Finally, we'll modify the SendToSwitch function to indicate that the // Finally, we'll modify the SendToSwitch function to indicate that the
// roasbeef -> luoji channel has insufficient capacity. // roasbeef -> luoji channel has insufficient capacity.
ctx.router.cfg.SendToSwitch = func(n *btcec.PublicKey, ctx.router.cfg.SendToSwitch = func(n [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if ctx.aliases["luoji"].IsEqual(n) { if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
// We'll first simulate an error from the first // We'll first simulate an error from the first
// outgoing link to simulate the channel from luo ji to // outgoing link to simulate the channel from luo ji to
// roasbeef not having enough capacity. // roasbeef not having enough capacity.
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey, ErrorSource: sourcePub,
FailureMessage: &lnwire.FailTemporaryChannelFailure{}, FailureMessage: &lnwire.FailTemporaryChannelFailure{},
} }
} }
@ -457,13 +467,13 @@ func TestAddProof(t *testing.T) {
// After utxo was recreated adding the edge without the proof. // After utxo was recreated adding the edge without the proof.
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1), AuthProof: nil,
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: nil,
} }
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@ -495,16 +505,17 @@ func TestIgnoreNodeAnnouncement(t *testing.T) {
t.Fatalf("unable to create router: %v", err) t.Fatalf("unable to create router: %v", err)
} }
pub := priv1.PubKey()
node := &channeldb.LightningNode{ node := &channeldb.LightningNode{
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0), LastUpdate: time.Unix(123, 0),
Addresses: testAddrs, Addresses: testAddrs,
PubKey: copyPubKey(priv1.PubKey()),
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "node11", Alias: "node11",
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
Features: testFeatures, Features: testFeatures,
} }
copy(node.PubKeyBytes[:], pub.SerializeCompressed())
err = ctx.router.AddNode(node) err = ctx.router.AddNode(node)
if !IsError(err, ErrIgnored) { if !IsError(err, ErrIgnored) {
@ -527,15 +538,21 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
t.Fatalf("unable to create router: %v", err) t.Fatalf("unable to create router: %v", err)
} }
var pub1 [33]byte
copy(pub1[:], priv1.PubKey().SerializeCompressed())
var pub2 [33]byte
copy(pub2[:], priv2.PubKey().SerializeCompressed())
// The two nodes we are about to add should not exist yet. // The two nodes we are about to add should not exist yet.
_, exists1, err := ctx.graph.HasLightningNode(priv1.PubKey()) _, exists1, err := ctx.graph.HasLightningNode(pub1)
if err != nil { if err != nil {
t.Fatalf("unable to query graph: %v", err) t.Fatalf("unable to query graph: %v", err)
} }
if exists1 { if exists1 {
t.Fatalf("node already existed") t.Fatalf("node already existed")
} }
_, exists2, err := ctx.graph.HasLightningNode(priv2.PubKey()) _, exists2, err := ctx.graph.HasLightningNode(pub2)
if err != nil { if err != nil {
t.Fatalf("unable to query graph: %v", err) t.Fatalf("unable to query graph: %v", err)
} }
@ -558,12 +575,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
edge := &channeldb.ChannelEdgeInfo{ edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: copyPubKey(priv1.PubKey()), NodeKey1Bytes: pub1,
NodeKey2: copyPubKey(priv2.PubKey()), NodeKey2Bytes: pub2,
BitcoinKey1: copyPubKey(bitcoinKey1), BitcoinKey1Bytes: pub1,
BitcoinKey2: copyPubKey(bitcoinKey2), BitcoinKey2Bytes: pub2,
AuthProof: nil, AuthProof: nil,
} }
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("expected to be able to add edge to the channel graph,"+ t.Fatalf("expected to be able to add edge to the channel graph,"+
@ -573,7 +590,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// We must add the edge policy to be able to use the edge for route // We must add the edge policy to be able to use the edge for route
// finding. // finding.
edgePolicy := &channeldb.ChannelEdgePolicy{ edgePolicy := &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,
@ -589,7 +606,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// Create edge in the other direction as well. // Create edge in the other direction as well.
edgePolicy = &channeldb.ChannelEdgePolicy{ edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,
@ -605,14 +622,14 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// After adding the edge between the two previously unknown nodes, they // After adding the edge between the two previously unknown nodes, they
// should have been added to the graph. // should have been added to the graph.
_, exists1, err = ctx.graph.HasLightningNode(priv1.PubKey()) _, exists1, err = ctx.graph.HasLightningNode(pub1)
if err != nil { if err != nil {
t.Fatalf("unable to query graph: %v", err) t.Fatalf("unable to query graph: %v", err)
} }
if !exists1 { if !exists1 {
t.Fatalf("node1 was not added to the graph") t.Fatalf("node1 was not added to the graph")
} }
_, exists2, err = ctx.graph.HasLightningNode(priv2.PubKey()) _, exists2, err = ctx.graph.HasLightningNode(pub2)
if err != nil { if err != nil {
t.Fatalf("unable to query graph: %v", err) t.Fatalf("unable to query graph: %v", err)
} }
@ -656,20 +673,20 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
edge = &channeldb.ChannelEdgeInfo{ edge = &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(), ChannelID: chanID.ToUint64(),
NodeKey1: pubKey1, AuthProof: nil,
NodeKey2: pubKey2,
BitcoinKey1: pubKey1,
BitcoinKey2: pubKey2,
AuthProof: nil,
} }
copy(edge.NodeKey1Bytes[:], node1Bytes)
copy(edge.NodeKey2Bytes[:], node2Bytes)
copy(edge.BitcoinKey1Bytes[:], node1Bytes)
copy(edge.BitcoinKey2Bytes[:], node2Bytes)
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge to the channel graph: %v.", err) t.Fatalf("unable to add edge to the channel graph: %v.", err)
} }
edgePolicy = &channeldb.ChannelEdgePolicy{ edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,
@ -684,7 +701,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
} }
edgePolicy = &channeldb.ChannelEdgePolicy{ edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig, SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
LastUpdate: time.Now(), LastUpdate: time.Now(),
TimeLockDelta: 10, TimeLockDelta: 10,
@ -716,12 +733,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0), LastUpdate: time.Unix(123, 0),
Addresses: testAddrs, Addresses: testAddrs,
PubKey: copyPubKey(priv1.PubKey()),
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "node11", Alias: "node11",
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
Features: testFeatures, Features: testFeatures,
} }
copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed())
if err := ctx.router.AddNode(n1); err != nil { if err := ctx.router.AddNode(n1); err != nil {
t.Fatalf("could not add node: %v", err) t.Fatalf("could not add node: %v", err)
@ -731,12 +748,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0), LastUpdate: time.Unix(123, 0),
Addresses: testAddrs, Addresses: testAddrs,
PubKey: copyPubKey(priv2.PubKey()),
Color: color.RGBA{1, 2, 3, 0}, Color: color.RGBA{1, 2, 3, 0},
Alias: "node22", Alias: "node22",
AuthSig: testSig, AuthSigBytes: testSig.Serialize(),
Features: testFeatures, Features: testFeatures,
} }
copy(n2.PubKeyBytes[:], priv2.PubKey().SerializeCompressed())
if err := ctx.router.AddNode(n2); err != nil { if err := ctx.router.AddNode(n2); err != nil {
t.Fatalf("could not add node: %v", err) t.Fatalf("could not add node: %v", err)
@ -865,36 +882,36 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
} }
edge1 := &channeldb.ChannelEdgeInfo{ edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1, ChannelID: chanID1,
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil { if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
edge2 := &channeldb.ChannelEdgeInfo{ edge2 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID2, ChannelID: chanID2,
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge2); err != nil { if err := ctx.router.AddEdge(edge2); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@ -940,7 +957,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
Graph: ctx.graph, Graph: ctx.graph,
Chain: ctx.chain, Chain: ctx.chain,
ChainView: ctx.chainView, ChainView: ctx.chainView,
SendToSwitch: func(_ *btcec.PublicKey, SendToSwitch: func(_ [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil return [32]byte{}, nil
}, },
@ -1067,36 +1084,40 @@ func TestDisconnectedBlocks(t *testing.T) {
} }
edge1 := &channeldb.ChannelEdgeInfo{ edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1, ChannelID: chanID1,
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1), BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2: copyPubKey(bitcoinKey2), BitcoinKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil { if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
edge2 := &channeldb.ChannelEdgeInfo{ edge2 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID2, ChannelID: chanID2,
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1), BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2: copyPubKey(bitcoinKey2), BitcoinKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge2); err != nil { if err := ctx.router.AddEdge(edge2); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@ -1207,18 +1228,18 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) {
t.Fatalf("unable to create test node: %v", err) t.Fatalf("unable to create test node: %v", err)
} }
edge1 := &channeldb.ChannelEdgeInfo{ edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1.ToUint64(), ChannelID: chanID1.ToUint64(),
NodeKey1: copyPubKey(node1.PubKey), NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2: copyPubKey(node2.PubKey), NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: &channeldb.ChannelAuthProof{ AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig, NodeSig1Bytes: testSig.Serialize(),
NodeSig2: testSig, NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1: testSig, BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2: testSig, BitcoinSig2Bytes: testSig.Serialize(),
}, },
} }
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil { if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }

@ -104,8 +104,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
v.chanAnnFinSignal[msg.ShortChannelID] = annFinCond v.chanAnnFinSignal[msg.ShortChannelID] = annFinCond
v.chanEdgeDependencies[msg.ShortChannelID] = annFinCond v.chanEdgeDependencies[msg.ShortChannelID] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeID1)] = annFinCond v.nodeAnnDependencies[Vertex(msg.NodeID1)] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeID2)] = annFinCond v.nodeAnnDependencies[Vertex(msg.NodeID2)] = annFinCond
} }
case *channeldb.ChannelEdgeInfo: case *channeldb.ChannelEdgeInfo:
@ -116,8 +116,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
v.chanAnnFinSignal[shortID] = annFinCond v.chanAnnFinSignal[shortID] = annFinCond
v.chanEdgeDependencies[shortID] = annFinCond v.chanEdgeDependencies[shortID] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeKey1)] = annFinCond v.nodeAnnDependencies[Vertex(msg.NodeKey1Bytes)] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeKey2)] = annFinCond v.nodeAnnDependencies[Vertex(msg.NodeKey2Bytes)] = annFinCond
} }
// These other types don't have any dependants, so no further // These other types don't have any dependants, so no further
@ -127,6 +127,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
case *lnwire.ChannelUpdate: case *lnwire.ChannelUpdate:
return return
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
// TODO(roasbeef): node ann needs to wait on existing channel updates
return return
case *channeldb.LightningNode: case *channeldb.LightningNode:
return return
@ -167,12 +168,12 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) {
shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
signal, ok = v.chanEdgeDependencies[shortID] signal, ok = v.chanEdgeDependencies[shortID]
case *channeldb.LightningNode: case *channeldb.LightningNode:
vertex := NewVertex(msg.PubKey) vertex := Vertex(msg.PubKeyBytes)
signal, ok = v.nodeAnnDependencies[vertex] signal, ok = v.nodeAnnDependencies[vertex]
case *lnwire.ChannelUpdate: case *lnwire.ChannelUpdate:
signal, ok = v.chanEdgeDependencies[msg.ShortChannelID] signal, ok = v.chanEdgeDependencies[msg.ShortChannelID]
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
vertex := NewVertex(msg.NodeID) vertex := Vertex(msg.NodeID)
signal, ok = v.nodeAnnDependencies[vertex] signal, ok = v.nodeAnnDependencies[vertex]
// Other types of jobs can be executed immediately, so we'll just // Other types of jobs can be executed immediately, so we'll just
@ -233,9 +234,9 @@ func (v *ValidationBarrier) SignalDependants(job interface{}) {
// map, as if we reach this point, then all dependants have already // map, as if we reach this point, then all dependants have already
// finished executing and we can proceed. // finished executing and we can proceed.
case *channeldb.LightningNode: case *channeldb.LightningNode:
delete(v.nodeAnnDependencies, NewVertex(msg.PubKey)) delete(v.nodeAnnDependencies, Vertex(msg.PubKeyBytes))
case *lnwire.NodeAnnouncement: case *lnwire.NodeAnnouncement:
delete(v.nodeAnnDependencies, NewVertex(msg.NodeID)) delete(v.nodeAnnDependencies, Vertex(msg.NodeID))
case *lnwire.ChannelUpdate: case *lnwire.ChannelUpdate:
delete(v.chanEdgeDependencies, msg.ShortChannelID) delete(v.chanEdgeDependencies, msg.ShortChannelID)
case *channeldb.ChannelEdgePolicy: case *channeldb.ChannelEdgePolicy:

@ -535,11 +535,14 @@ func (r *rpcServer) VerifyMessage(ctx context.Context,
} }
pubKeyHex := hex.EncodeToString(pubKey.SerializeCompressed()) pubKeyHex := hex.EncodeToString(pubKey.SerializeCompressed())
var pub [33]byte
copy(pub[:], pubKey.SerializeCompressed())
// Query the channel graph to ensure a node in the network with active // Query the channel graph to ensure a node in the network with active
// channels signed the message. // channels signed the message.
// TODO(phlip9): Require valid nodes to have capital in active channels. // TODO(phlip9): Require valid nodes to have capital in active channels.
graph := r.server.chanDB.ChannelGraph() graph := r.server.chanDB.ChannelGraph()
_, active, err := graph.HasLightningNode(pubKey) _, active, err := graph.HasLightningNode(pub)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to query graph: %v", err) return nil, fmt.Errorf("failed to query graph: %v", err)
} }
@ -1576,8 +1579,8 @@ func (r *rpcServer) savePayment(route *routing.Route, amount lnwire.MilliSatoshi
paymentPath := make([][33]byte, len(route.Hops)) paymentPath := make([][33]byte, len(route.Hops))
for i, hop := range route.Hops { for i, hop := range route.Hops {
hopPub := hop.Channel.Node.PubKey.SerializeCompressed() hopPub := hop.Channel.Node.PubKeyBytes
copy(paymentPath[i][:], hopPub) copy(paymentPath[i][:], hopPub[:])
} }
payment := &channeldb.OutgoingPayment{ payment := &channeldb.OutgoingPayment{
@ -2407,7 +2410,7 @@ func (r *rpcServer) DescribeGraph(ctx context.Context,
nodeColor := fmt.Sprintf("#%02x%02x%02x", node.Color.R, node.Color.G, node.Color.B) nodeColor := fmt.Sprintf("#%02x%02x%02x", node.Color.R, node.Color.G, node.Color.B)
resp.Nodes = append(resp.Nodes, &lnrpc.LightningNode{ resp.Nodes = append(resp.Nodes, &lnrpc.LightningNode{
LastUpdate: uint32(node.LastUpdate.Unix()), LastUpdate: uint32(node.LastUpdate.Unix()),
PubKey: hex.EncodeToString(node.PubKey.SerializeCompressed()), PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
Addresses: nodeAddrs, Addresses: nodeAddrs,
Alias: node.Alias, Alias: node.Alias,
Color: nodeColor, Color: nodeColor,
@ -2455,8 +2458,8 @@ func marshalDbEdge(edgeInfo *channeldb.ChannelEdgeInfo,
ChanPoint: edgeInfo.ChannelPoint.String(), ChanPoint: edgeInfo.ChannelPoint.String(),
// TODO(roasbeef): update should be on edge info itself // TODO(roasbeef): update should be on edge info itself
LastUpdate: uint32(lastUpdate), LastUpdate: uint32(lastUpdate),
Node1Pub: hex.EncodeToString(edgeInfo.NodeKey1.SerializeCompressed()), Node1Pub: hex.EncodeToString(edgeInfo.NodeKey1Bytes[:]),
Node2Pub: hex.EncodeToString(edgeInfo.NodeKey2.SerializeCompressed()), Node2Pub: hex.EncodeToString(edgeInfo.NodeKey2Bytes[:]),
Capacity: int64(edgeInfo.Capacity), Capacity: int64(edgeInfo.Capacity),
} }

@ -258,11 +258,11 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
HaveNodeAnnouncement: true, HaveNodeAnnouncement: true,
LastUpdate: time.Now(), LastUpdate: time.Now(),
Addresses: selfAddrs, Addresses: selfAddrs,
PubKey: privKey.PubKey(),
Alias: nodeAlias.String(), Alias: nodeAlias.String(),
Features: s.globalFeatures, Features: s.globalFeatures,
Color: color, Color: color,
} }
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
// If our information has changed since our last boot, then we'll // If our information has changed since our last boot, then we'll
// re-sign our node announcement so a fresh authenticated version of it // re-sign our node announcement so a fresh authenticated version of it
@ -272,31 +272,35 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
nodeAnn := &lnwire.NodeAnnouncement{ nodeAnn := &lnwire.NodeAnnouncement{
Timestamp: uint32(selfNode.LastUpdate.Unix()), Timestamp: uint32(selfNode.LastUpdate.Unix()),
Addresses: selfNode.Addresses, Addresses: selfNode.Addresses,
NodeID: selfNode.PubKey, NodeID: selfNode.PubKeyBytes,
Alias: nodeAlias, Alias: nodeAlias,
Features: selfNode.Features.RawFeatureVector, Features: selfNode.Features.RawFeatureVector,
RGBColor: color, RGBColor: color,
} }
selfNode.AuthSig, err = discovery.SignAnnouncement(s.nodeSigner, authSig, err := discovery.SignAnnouncement(
s.identityPriv.PubKey(), nodeAnn, s.nodeSigner, s.identityPriv.PubKey(), nodeAnn,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate signature for "+ return nil, fmt.Errorf("unable to generate signature for "+
"self node announcement: %v", err) "self node announcement: %v", err)
} }
selfNode.AuthSigBytes = authSig.Serialize()
s.currentNodeAnn = nodeAnn
if err := chanGraph.SetSourceNode(selfNode); err != nil { if err := chanGraph.SetSourceNode(selfNode); err != nil {
return nil, fmt.Errorf("can't set self node: %v", err) return nil, fmt.Errorf("can't set self node: %v", err)
} }
nodeAnn.Signature = selfNode.AuthSig nodeAnn.Signature, err = lnwire.NewSigFromRawSignature(selfNode.AuthSigBytes)
s.currentNodeAnn = nodeAnn if err != nil {
return nil, err
}
s.chanRouter, err = routing.New(routing.Config{ s.chanRouter, err = routing.New(routing.Config{
Graph: chanGraph, Graph: chanGraph,
Chain: cc.chainIO, Chain: cc.chainIO,
ChainView: cc.chainView, ChainView: cc.chainView,
SendToSwitch: func(firstHop *btcec.PublicKey, SendToSwitch: func(firstHopPub [33]byte,
htlcAdd *lnwire.UpdateAddHTLC, htlcAdd *lnwire.UpdateAddHTLC,
circuit *sphinx.Circuit) ([32]byte, error) { circuit *sphinx.Circuit) ([32]byte, error) {
@ -307,9 +311,6 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
OnionErrorDecrypter: sphinx.NewOnionErrorDecrypter(circuit), OnionErrorDecrypter: sphinx.NewOnionErrorDecrypter(circuit),
} }
var firstHopPub [33]byte
copy(firstHopPub[:], firstHop.SerializeCompressed())
return s.htlcSwitch.SendHTLC(firstHopPub, htlcAdd, errorDecryptor) return s.htlcSwitch.SendHTLC(firstHopPub, htlcAdd, errorDecryptor)
}, },
ChannelPruneExpiry: time.Duration(time.Hour * 24 * 14), ChannelPruneExpiry: time.Duration(time.Hour * 24 * 14),
@ -806,11 +807,19 @@ func (s *server) genNodeAnnouncement(
} }
s.currentNodeAnn.Timestamp = newStamp s.currentNodeAnn.Timestamp = newStamp
s.currentNodeAnn.Signature, err = discovery.SignAnnouncement( sig, err := discovery.SignAnnouncement(
s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn, s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn,
) )
if err != nil {
return lnwire.NodeAnnouncement{}, err
}
return *s.currentNodeAnn, err s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return lnwire.NodeAnnouncement{}, err
}
return *s.currentNodeAnn, nil
} }
type nodeAddresses struct { type nodeAddresses struct {
@ -870,7 +879,7 @@ func (s *server) establishPersistentConnections() error {
_ *channeldb.ChannelEdgeInfo, _ *channeldb.ChannelEdgeInfo,
policy, _ *channeldb.ChannelEdgePolicy) error { policy, _ *channeldb.ChannelEdgePolicy) error {
pubStr := string(policy.Node.PubKey.SerializeCompressed()) pubStr := string(policy.Node.PubKeyBytes[:])
// Add addresses from channel graph/NodeAnnouncements to the // Add addresses from channel graph/NodeAnnouncements to the
// list of addresses we'll connect to. If there are duplicates // list of addresses we'll connect to. If there are duplicates
@ -906,11 +915,15 @@ func (s *server) establishPersistentConnections() error {
} }
} }
nodeAddrsMap[pubStr] = &nodeAddresses{ n := &nodeAddresses{
pubKey: policy.Node.PubKey,
addresses: addrs, addresses: addrs,
} }
n.pubKey, err = policy.Node.PubKey()
if err != nil {
return err
}
nodeAddrsMap[pubStr] = n
return nil return nil
}) })
if err != nil && err != channeldb.ErrGraphNoEdgesFound { if err != nil && err != channeldb.ErrGraphNoEdgesFound {

@ -327,8 +327,8 @@ func Decode(invoice string) (*Invoice, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var sigBytes [64]byte var sig lnwire.Sig
copy(sigBytes[:], sigBase256[:64]) copy(sig[:], sigBase256[:64])
recoveryID := sigBase256[64] recoveryID := sigBase256[64]
// The signature is over the hrp + the data the invoice, encoded in // The signature is over the hrp + the data the invoice, encoded in
@ -347,8 +347,7 @@ func Decode(invoice string) (*Invoice, error) {
// If the destination pubkey was provided as a tagged field, use that // If the destination pubkey was provided as a tagged field, use that
// to verify the signature, if not do public key recovery. // to verify the signature, if not do public key recovery.
if decodedInvoice.Destination != nil { if decodedInvoice.Destination != nil {
var signature *btcec.Signature signature, err := sig.ToSignature()
err := lnwire.DeserializeSigFromWire(&signature, sigBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to deserialize "+ return nil, fmt.Errorf("unable to deserialize "+
"signature: %v", err) "signature: %v", err)
@ -358,7 +357,7 @@ func Decode(invoice string) (*Invoice, error) {
} }
} else { } else {
headerByte := recoveryID + 27 + 4 headerByte := recoveryID + 27 + 4
compactSign := append([]byte{headerByte}, sigBytes[:]...) compactSign := append([]byte{headerByte}, sig[:]...)
pubkey, _, err := btcec.RecoverCompact(btcec.S256(), pubkey, _, err := btcec.RecoverCompact(btcec.S256(),
compactSign, hash) compactSign, hash)
if err != nil { if err != nil {
@ -449,18 +448,18 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) {
// From the header byte we can extract the recovery ID, and the last 64 // From the header byte we can extract the recovery ID, and the last 64
// bytes encode the signature. // bytes encode the signature.
recoveryID := sign[0] - 27 - 4 recoveryID := sign[0] - 27 - 4
var sigBytes [64]byte var sig lnwire.Sig
copy(sigBytes[:], sign[1:]) copy(sig[:], sign[1:])
// If the pubkey field was explicitly set, it must be set to the pubkey // If the pubkey field was explicitly set, it must be set to the pubkey
// used to create the signature. // used to create the signature.
if invoice.Destination != nil { if invoice.Destination != nil {
var signature *btcec.Signature signature, err := sig.ToSignature()
err = lnwire.DeserializeSigFromWire(&signature, sigBytes)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to deserialize "+ return "", fmt.Errorf("unable to deserialize "+
"signature: %v", err) "signature: %v", err)
} }
valid := signature.Verify(hash, invoice.Destination) valid := signature.Verify(hash, invoice.Destination)
if !valid { if !valid {
return "", fmt.Errorf("signature does not match " + return "", fmt.Errorf("signature does not match " +
@ -469,7 +468,7 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) {
} }
// Convert the signature to base32 before writing it to the buffer. // Convert the signature to base32 before writing it to the buffer.
signBase32, err := bech32.ConvertBits(append(sigBytes[:], recoveryID), 8, 5, true) signBase32, err := bech32.ConvertBits(append(sig[:], recoveryID), 8, 5, true)
if err != nil { if err != nil {
return "", err return "", err
} }