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"
"fmt"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"

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

@ -10,7 +10,6 @@ import (
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire"
"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
// we can broadcast it to the network.
matchingSig := c.priorFeeOffers[remoteProposedFee].Signature
localSig := append(
matchingSig.Serialize(), byte(txscript.SigHashAll),
)
remoteSig := append(
closeSignedMsg.Signature.Serialize(), byte(txscript.SigHashAll),
)
localSigBytes := matchingSig.ToSignatureBytes()
localSig := append(localSigBytes, byte(txscript.SigHashAll))
remoteSigBytes := closeSignedMsg.Signature.ToSignatureBytes()
remoteSig := append(remoteSigBytes, byte(txscript.SigHashAll))
closeTx, finalLocalBalance, err := c.cfg.channel.CompleteCooperativeClose(
localSig, remoteSig, c.localDeliveryScript,
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
// not.
c.lastFeeProposal = fee
parsedSig, err := btcec.ParseSignature(rawSig, btcec.S256())
parsedSig, err := lnwire.NewSigFromRawSignature(rawSig)
if err != nil {
return nil, err
}

@ -81,6 +81,8 @@ var (
Index: 0,
}
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), key[:])
wireSig, _ = lnwire.NewSigFromSignature(testSig)
)
// makeTestDB creates a new instance of the ChannelDB for testing purposes. A
@ -428,10 +430,10 @@ func TestChannelStateTransition(t *testing.T) {
Commitment: remoteCommit,
CommitSig: &lnwire.CommitSig{
ChanID: lnwire.ChannelID(key),
CommitSig: testSig,
HtlcSigs: []*btcec.Signature{
testSig,
testSig,
CommitSig: wireSig,
HtlcSigs: []lnwire.Sig{
wireSig,
wireSig,
},
},
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
// algorithms.
func (c *ChannelGraph) SetSourceNode(node *LightningNode) error {
nodePub := node.PubKey.SerializeCompressed()
nodePubBytes := node.PubKeyBytes[:]
return c.db.Update(func(tx *bolt.Tx) error {
// First grab the nodes bucket which stores the mapping from
// 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
// public key.
if err := nodes.Put(sourceKey, nodePub); err != nil {
if err := nodes.Put(sourceKey, nodePubBytes); err != nil {
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
// attached to it for each outgoing edge.
type LightningNode struct {
// PubKey is the node's long-term identity public key. This key will be
// used to authenticated any advertisements/updates sent by the node.
PubKey *btcec.PublicKey
// PubKeyBytes is the raw bytes of the public key of the target node.
PubKeyBytes [33]byte
pubKey *btcec.PublicKey
// HaveNodeAnnouncement indicates whether we received a node announcement
// for this particular node. If true, the remaining fields will be set,
// if false only the PubKey is known for this node.
// HaveNodeAnnouncement indicates whether we received a node
// announcement for this particular node. If true, the remaining fields
// will be set, if false only the PubKey is known for this node.
HaveNodeAnnouncement bool
// 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.
Alias string
// AuthSig is a signature under the advertised public key which serves
// to authenticate the attributes announced by this node.
//
// TODO(roasbeef): hook into serialization once full verification is in
AuthSig *btcec.Signature
// AuthSigBytes is the raw signature under the advertised public key
// which serves to authenticate the attributes announced by this node.
AuthSigBytes []byte
// Features is the list of protocol features supported by this node.
Features *lnwire.FeatureVector
@ -1016,6 +1015,42 @@ type LightningNode struct {
// 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
// key. If the node isn't found in the database, then ErrGraphNodeNotFound is
// 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
// with a true boolean. Otherwise, an empty time.Time is returned with a false
// boolean.
func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool, error) {
func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, error) {
var (
updateTime time.Time
exists bool
)
nodePub := pub.SerializeCompressed()
err := c.db.View(func(tx *bolt.Tx) error {
// First grab the nodes bucket which stores the mapping from
// 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
// exit early.
nodeBytes := nodes.Get(nodePub)
nodeBytes := nodes.Get(nodePub[:])
if nodeBytes == nil {
exists = false
return nil
@ -1119,7 +1153,11 @@ func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool,
func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
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 {
nodes := tx.Bucket(nodeBucket)
@ -1172,7 +1210,12 @@ func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
// We'll also fetch the incoming edge so this
// 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(
edges, chanID, incomingNode, nodes,
)
@ -1227,29 +1270,21 @@ type ChannelEdgeInfo struct {
// * must add chain hash to prefix as well
ChainHash chainhash.Hash
// 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.
NodeKey1 *btcec.PublicKey
// NodeKey1Bytes is the raw public key of the first node.
NodeKey1Bytes [33]byte
nodeKey1 *btcec.PublicKey
// 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.
NodeKey2 *btcec.PublicKey
// NodeKey2Bytes is the raw public key of the first node.
NodeKey2Bytes [33]byte
nodeKey2 *btcec.PublicKey
// 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.
BitcoinKey1 *btcec.PublicKey
// BitcoinKey1Bytes is the raw public key of the first node.
BitcoinKey1Bytes [33]byte
bitcoinKey1 *btcec.PublicKey
// 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.
BitcoinKey2 *btcec.PublicKey
// BitcoinKey2Bytes is the raw public key of the first node.
BitcoinKey2Bytes [33]byte
bitcoinKey2 *btcec.PublicKey
// Features is an opaque byte slice that encodes the set of channel
// specific features that this channel edge supports.
@ -1269,6 +1304,107 @@ type ChannelEdgeInfo struct {
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
// channel. Using the four signatures contained in the struct, and some
// 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 ||
// features.
type ChannelAuthProof struct {
// NodeSig1 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.
NodeSig1 *btcec.Signature
// nodeSig1 is a cached instance of the first node signature.
nodeSig1 *btcec.Signature
// NodeSig2 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.
NodeSig2 *btcec.Signature
// NodeSig1Bytes are the raw bytes of the first node signature encoded
// in DER format.
NodeSig1Bytes []byte
// BitcoinSig1 is the signature using the public key of the first node
// that was used in the channel's multi-sig output.
BitcoinSig1 *btcec.Signature
// nodeSig2 is a cached instance of the second node signature.
nodeSig2 *btcec.Signature
// BitcoinSig2 is the signature using the public key of the second node
// that was used in the channel's multi-sig output.
BitcoinSig2 *btcec.Signature
// NodeSig2Bytes are the raw bytes of the second node signature
// encoded in DER format.
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
// least one of the signatures are equal to nil.
func (p *ChannelAuthProof) IsEmpty() bool {
return p.NodeSig1 == nil ||
p.NodeSig2 == nil ||
p.BitcoinSig1 == nil ||
p.BitcoinSig2 == nil
func (c *ChannelAuthProof) IsEmpty() bool {
return len(c.NodeSig1Bytes) == 0 ||
len(c.NodeSig2Bytes) == 0 ||
len(c.BitcoinSig1Bytes) == 0 ||
len(c.BitcoinSig2Bytes) == 0
}
// 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
// utilized during path finding.
type ChannelEdgePolicy struct {
// Signature is a channel announcement signature, which is needed for
// proper edge policy announcement.
Signature *btcec.Signature
// SigBytes is the raw bytes of the signature of the channel edge
// policy. We'll only parse these if the caller needs to access the
// 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
// bytes are the block height, the next 3 the index within the block,
@ -1352,6 +1584,26 @@ type ChannelEdgePolicy struct {
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
// the channel identified by the funding outpoint. If the channel can't be
// 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
)
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.
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 {
return err
}
@ -1630,8 +1886,12 @@ func fetchLightningNode(nodeBucket *bolt.Bucket,
}
func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
var (
scratch [8]byte
err error
)
node := &LightningNode{}
var scratch [8]byte
if _, err := r.Read(scratch[:]); err != nil {
return nil, err
@ -1640,13 +1900,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
unix := int64(byteOrder.Uint64(scratch[:]))
node.LastUpdate = time.Unix(unix, 0)
var pub [33]byte
if _, err := r.Read(pub[:]); err != nil {
return nil, err
}
var err error
node.PubKey, err = btcec.ParsePubKey(pub[:], btcec.S256())
if err != nil {
if _, err := io.ReadFull(r, node.PubKeyBytes[:]); err != nil {
return nil, err
}
@ -1706,12 +1960,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
}
node.Addresses = addresses
sigBytes, err := wire.ReadVarBytes(r, 0, 80, "sig")
if err != nil {
return nil, err
}
node.AuthSig, err = btcec.ParseSignature(sigBytes, btcec.S256())
node.AuthSigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
if err != nil {
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 {
var b bytes.Buffer
if _, err := b.Write(edgeInfo.NodeKey1.SerializeCompressed()); err != nil {
if _, err := b.Write(edgeInfo.NodeKey1Bytes[:]); err != nil {
return err
}
if _, err := b.Write(edgeInfo.NodeKey2.SerializeCompressed()); err != nil {
if _, err := b.Write(edgeInfo.NodeKey2Bytes[:]); err != nil {
return err
}
if _, err := b.Write(edgeInfo.BitcoinKey1.SerializeCompressed()); err != nil {
if _, err := b.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil {
return err
}
if _, err := b.Write(edgeInfo.BitcoinKey2.SerializeCompressed()); err != nil {
if _, err := b.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil {
return err
}
@ -1742,10 +1991,10 @@ func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [
authProof := edgeInfo.AuthProof
var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte
if authProof != nil {
nodeSig1 = authProof.NodeSig1.Serialize()
nodeSig2 = authProof.NodeSig2.Serialize()
bitcoinSig1 = authProof.BitcoinSig1.Serialize()
bitcoinSig2 = authProof.BitcoinSig2.Serialize()
nodeSig1 = authProof.NodeSig1Bytes
nodeSig2 = authProof.NodeSig2Bytes
bitcoinSig1 = authProof.BitcoinSig1Bytes
bitcoinSig2 = authProof.BitcoinSig2Bytes
}
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) {
var (
err error
pubKeyBytes [33]byte
edgeInfo = &ChannelEdgeInfo{}
err error
edgeInfo = &ChannelEdgeInfo{}
)
readKey := func() (*btcec.PublicKey, error) {
if _, err := io.ReadFull(r, pubKeyBytes[:]); err != nil {
return nil, err
}
return btcec.ParsePubKey(pubKeyBytes[:], btcec.S256())
}
edgeInfo.NodeKey1, err = readKey()
if err != nil {
if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil {
return nil, err
}
edgeInfo.NodeKey2, err = readKey()
if err != nil {
if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil {
return nil, err
}
edgeInfo.BitcoinKey1, err = readKey()
if err != nil {
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil {
return nil, err
}
edgeInfo.BitcoinKey2, err = readKey()
if err != nil {
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil {
return nil, err
}
@ -1828,32 +2064,23 @@ func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) {
proof := &ChannelAuthProof{}
readSig := func() (*btcec.Signature, error) {
sigBytes, err := 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
readSig := func() ([]byte, error) {
return wire.ReadVarBytes(r, 0, 80, "sigs")
}
proof.NodeSig1, err = readSig()
proof.NodeSig1Bytes, err = readSig()
if err != nil {
return nil, err
}
proof.NodeSig2, err = readSig()
proof.NodeSig2Bytes, err = readSig()
if err != nil {
return nil, err
}
proof.BitcoinSig1, err = readSig()
proof.BitcoinSig1Bytes, err = readSig()
if err != nil {
return nil, err
}
proof.BitcoinSig2, err = readSig()
proof.BitcoinSig2Bytes, err = readSig()
if err != nil {
return nil, err
}
@ -1887,7 +2114,7 @@ func putChanEdgePolicy(edges *bolt.Bucket, edge *ChannelEdgePolicy, from, to []b
var b bytes.Buffer
err := wire.WriteVarBytes(&b, 0, edge.Signature.Serialize())
err := wire.WriteVarBytes(&b, 0, edge.SigBytes)
if err != nil {
return err
}
@ -1993,11 +2220,7 @@ func deserializeChanEdgePolicy(r io.Reader,
if err != nil {
return nil, err
}
edge.Signature, err = btcec.ParseSignature(sigBytes, btcec.S256())
if err != nil {
return nil, err
}
edge.SigBytes = sigBytes
if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil {
return nil, err

@ -50,17 +50,19 @@ func createTestVertex(db *DB) (*LightningNode, error) {
}
pub := priv.PubKey().SerializeCompressed()
return &LightningNode{
n := &LightningNode{
HaveNodeAnnouncement: true,
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(updateTime, 0),
PubKey: priv.PubKey(),
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + string(pub[:]),
Features: testFeatures,
Addresses: testAddrs,
db: db,
}, nil
}
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
return n, nil
}
func TestNodeInsertionAndDeletion(t *testing.T) {
@ -79,15 +81,15 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
_, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:])
node := &LightningNode{
HaveNodeAnnouncement: true,
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(1232342, 0),
PubKey: testPub,
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek",
Features: testFeatures,
Addresses: testAddrs,
db: db,
}
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
// First, insert the node into the graph DB. This should succeed
// without any errors.
@ -102,7 +104,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
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)
} else if !exists {
t.Fatalf("node should be found but wasn't")
@ -144,9 +146,9 @@ func TestPartialNode(t *testing.T) {
// PubKey set.
_, testPub := btcec.PrivKeyFromBytes(btcec.S256(), key[:])
node := &LightningNode{
PubKey: testPub,
HaveNodeAnnouncement: false,
}
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
if err := graph.AddLightningNode(node); err != nil {
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)
}
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)
} else if !exists {
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
// LastUpdate and db set to satisfy compareNodes())
node = &LightningNode{
PubKey: testPub,
HaveNodeAnnouncement: false,
LastUpdate: time.Unix(0, 0),
db: db,
}
copy(node.PubKeyBytes[:], testPub.SerializeCompressed())
if err := compareNodes(node, dbNode); err != nil {
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
// related to the node.
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
@ -218,7 +220,11 @@ func TestAliasLookup(t *testing.T) {
// Next, attempt to lookup the alias. The alias should exactly match
// 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 {
t.Fatalf("unable to find alias: %v", err)
}
@ -232,7 +238,11 @@ func TestAliasLookup(t *testing.T) {
if err != nil {
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 {
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
// 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{
ChannelID: chanID,
ChainHash: key,
NodeKey1: node1.PubKey,
NodeKey2: node2.PubKey,
BitcoinKey1: node1.PubKey,
BitcoinKey2: node2.PubKey,
ChannelID: chanID,
ChainHash: key,
AuthProof: &ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
ChannelPoint: outpoint,
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 {
t.Fatalf("unable to create channel edge: %v", err)
@ -413,22 +431,26 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
Index: outPointIndex,
}
node1Pub, _ := node1.PubKey()
node2Pub, _ := node2.PubKey()
edgeInfo := ChannelEdgeInfo{
ChannelID: shortChanID.ToUint64(),
ChainHash: key,
NodeKey1: node1.PubKey,
NodeKey2: node2.PubKey,
BitcoinKey1: node1.PubKey,
BitcoinKey2: node2.PubKey,
ChannelID: shortChanID.ToUint64(),
ChainHash: key,
AuthProof: &ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
ChannelPoint: outpoint,
Capacity: 9000,
}
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.NodeKey2Bytes[:], node2Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey2Bytes[:], node2Pub.SerializeCompressed())
return edgeInfo
}
@ -530,16 +552,16 @@ func assertEdgeInfoEqual(t *testing.T, e1 *ChannelEdgeInfo,
e2.ChainHash)
}
if !e1.NodeKey1.IsEqual(e2.NodeKey1) {
if !bytes.Equal(e1.NodeKey1Bytes[:], e2.NodeKey1Bytes[:]) {
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")
}
if !e1.BitcoinKey1.IsEqual(e2.BitcoinKey1) {
if !bytes.Equal(e1.BitcoinKey1Bytes[:], e2.BitcoinKey1Bytes[:]) {
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")
}
@ -548,18 +570,18 @@ func assertEdgeInfoEqual(t *testing.T, e1 *ChannelEdgeInfo,
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",
spew.Sdump(e1.AuthProof.NodeSig1),
spew.Sdump(e2.AuthProof.NodeSig1))
spew.Sdump(e1.AuthProof.NodeSig1Bytes),
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")
}
if !e1.AuthProof.BitcoinSig1.IsEqual(e2.AuthProof.BitcoinSig1) {
if !bytes.Equal(e1.AuthProof.BitcoinSig1Bytes, e2.AuthProof.BitcoinSig1Bytes) {
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")
}
@ -606,9 +628,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
firstNode *LightningNode
secondNode *LightningNode
)
node1Bytes := node1.PubKey.SerializeCompressed()
node2Bytes := node2.PubKey.SerializeCompressed()
if bytes.Compare(node1Bytes, node2Bytes) == -1 {
if bytes.Compare(node1.PubKeyBytes[:], node2.PubKeyBytes[:]) == -1 {
firstNode = node1
secondNode = node2
} else {
@ -627,21 +647,21 @@ func TestEdgeInfoUpdates(t *testing.T) {
// Add the new edge to the database, this should proceed without any
// errors.
edgeInfo := &ChannelEdgeInfo{
ChannelID: chanID,
ChainHash: key,
NodeKey1: firstNode.PubKey,
NodeKey2: secondNode.PubKey,
BitcoinKey1: firstNode.PubKey,
BitcoinKey2: secondNode.PubKey,
ChannelID: chanID,
ChainHash: key,
AuthProof: &ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
ChannelPoint: outpoint,
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 {
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
// update for both edges.
edge1 := &ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: chanID,
LastUpdate: time.Unix(433453, 0),
Flags: 0,
@ -661,7 +681,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
db: db,
}
edge2 := &ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: chanID,
LastUpdate: time.Unix(124234, 0),
Flags: 1,
@ -796,9 +816,7 @@ func TestGraphTraversal(t *testing.T) {
// Determine which node is "smaller", we'll need this in order to
// properly create the edges for the graph.
var firstNode, secondNode *LightningNode
node1Bytes := nodes[0].PubKey.SerializeCompressed()
node2Bytes := nodes[1].PubKey.SerializeCompressed()
if bytes.Compare(node1Bytes, node2Bytes) == -1 {
if bytes.Compare(nodes[0].PubKeyBytes[:], nodes[1].PubKeyBytes[:]) == -1 {
firstNode = nodes[0]
secondNode = nodes[1]
} else {
@ -818,21 +836,21 @@ func TestGraphTraversal(t *testing.T) {
}
edgeInfo := ChannelEdgeInfo{
ChannelID: chanID,
ChainHash: key,
NodeKey1: nodes[0].PubKey,
NodeKey2: nodes[1].PubKey,
BitcoinKey1: nodes[0].PubKey,
BitcoinKey2: nodes[1].PubKey,
ChannelID: chanID,
ChainHash: key,
AuthProof: &ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
ChannelPoint: op,
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)
if err != nil {
t.Fatalf("unable to add node: %v", err)
@ -843,7 +861,7 @@ func TestGraphTraversal(t *testing.T) {
edge := randEdgePolicy(chanID, op, db)
edge.Flags = 0
edge.Node = secondNode
edge.Signature = testSig
edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err)
}
@ -853,7 +871,7 @@ func TestGraphTraversal(t *testing.T) {
edge = randEdgePolicy(chanID, op, db)
edge.Flags = 1
edge.Node = firstNode
edge.Signature = testSig
edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil {
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
// 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")
}
// The incoming edge should also indicate that it's pointing to
// the origin node.
if !inEdge.Node.PubKey.IsEqual(firstNode.PubKey) {
if !bytes.Equal(inEdge.Node.PubKeyBytes[:], firstNode.PubKeyBytes[:]) {
return fmt.Errorf("wrong outgoing edge")
}
@ -1008,22 +1026,21 @@ func TestGraphPruning(t *testing.T) {
channelPoints = append(channelPoints, &op)
edgeInfo := ChannelEdgeInfo{
ChannelID: chanID,
ChainHash: key,
NodeKey1: graphNodes[i].PubKey,
NodeKey2: graphNodes[i+1].PubKey,
BitcoinKey1: graphNodes[i].PubKey,
BitcoinKey2: graphNodes[i+1].PubKey,
ChannelID: chanID,
ChainHash: key,
AuthProof: &ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
ChannelPoint: op,
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 {
t.Fatalf("unable to add node: %v", err)
}
@ -1033,7 +1050,7 @@ func TestGraphPruning(t *testing.T) {
edge := randEdgePolicy(chanID, op, db)
edge.Flags = 0
edge.Node = graphNodes[i]
edge.Signature = testSig
edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil {
t.Fatalf("unable to update edge: %v", err)
}
@ -1043,7 +1060,7 @@ func TestGraphPruning(t *testing.T) {
edge = randEdgePolicy(chanID, op, db)
edge.Flags = 1
edge.Node = graphNodes[i]
edge.Signature = testSig
edge.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(edge); err != nil {
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 "+
"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 "+
"got %#v", a.PubKey, b.PubKey)
"got %#v", a.PubKeyBytes, b.PubKeyBytes)
}
if !reflect.DeepEqual(a.Color, b.Color) {
return fmt.Errorf("Color doesn't match: expected %#v, \n "+

@ -21,8 +21,8 @@ func TestWaitingProofStore(t *testing.T) {
defer cleanup()
proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures{
NodeSignature: testSig,
BitcoinSignature: testSig,
NodeSignature: wireSig,
BitcoinSignature: wireSig,
})
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
// 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")
}
// If that checks out, then we'll verify that the second bitcoin
// signature is a valid signature of the bitcoin public key over hash
// digest as well.
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")
}
// Both node signatures attached should indeed be a valid 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")
}
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")
}
@ -61,17 +94,26 @@ func ValidateNodeAnn(a *lnwire.NodeAnnouncement) error {
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
// return an error so this node announcement can be rejected.
dataHash := chainhash.DoubleHashB(data)
if !a.Signature.Verify(dataHash, copyPubKey(a.NodeID)) {
if !nodeSig.Verify(dataHash, nodeKey) {
var msgBuf bytes.Buffer
if _, err := lnwire.WriteMessage(&msgBuf, a, 0); err != nil {
return err
}
return errors.Errorf("signature on NodeAnnouncement(%x) is "+
"invalid: %x", a.NodeID.SerializeCompressed(),
"invalid: %x", nodeKey.SerializeCompressed(),
msgBuf.Bytes())
}
@ -90,7 +132,12 @@ func ValidateChannelUpdateAnn(pubKey *btcec.PublicKey,
}
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 "+
"update %v", spew.Sdump(a))
}

@ -157,17 +157,17 @@ type AuthenticatedGossiper struct {
// TODO(roasbeef): limit premature networkMsgs to N
prematureAnnouncements map[uint32][]*networkMsg
// prematureChannelUpdates is a map of ChannelUpdates we have
// received that wasn't associated with any channel we know about.
// We store them temporarily, such that we can reprocess them when
// a ChannelAnnouncement for the channel is received.
// prematureChannelUpdates is a map of ChannelUpdates we have received
// that wasn't associated with any channel we know about. We store
// them temporarily, such that we can reprocess them when a
// ChannelAnnouncement for the channel is received.
prematureChannelUpdates map[uint64][]*networkMsg
pChanUpdMtx sync.Mutex
// waitingProofs is a persistent storage of partial channel proof
// announcement messages. We use it to buffer half of the material
// needed to reconstruct a full authenticated channel announcement. Once
// we receive the other half the channel proof, we'll be able to
// needed to reconstruct a full authenticated channel announcement.
// 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.
waitingProofs *channeldb.WaitingProofStore
@ -176,8 +176,8 @@ type AuthenticatedGossiper struct {
// networkHandler.
networkMsgs chan *networkMsg
// chanPolicyUpdates is a channel that requests to update the forwarding
// policy of a set of channels is sent over.
// chanPolicyUpdates is a channel that requests to update the
// forwarding policy of a set of channels is sent over.
chanPolicyUpdates chan *chanPolicyUpdateRequest
// 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.
channelMtx *multimutex.Mutex
rejectMtx sync.RWMutex
recentRejects map[uint64]struct{}
sync.Mutex
}
@ -214,6 +217,7 @@ func New(cfg Config, selfKey *btcec.PublicKey) (*AuthenticatedGossiper, error) {
prematureChannelUpdates: make(map[uint64][]*networkMsg),
waitingProofs: storage,
channelMtx: multimutex.NewMutex(),
recentRejects: make(map[uint64]struct{}),
}, nil
}
@ -232,17 +236,22 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// containing all the messages to be sent to the target peer.
var announceMessages []lnwire.Message
makeNodeAnn := func(n *channeldb.LightningNode) *lnwire.NodeAnnouncement {
makeNodeAnn := func(n *channeldb.LightningNode) (*lnwire.NodeAnnouncement, error) {
alias, _ := lnwire.NewNodeAlias(n.Alias)
wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes)
if err != nil {
return nil, err
}
return &lnwire.NodeAnnouncement{
Signature: n.AuthSig,
Signature: wireSig,
Timestamp: uint32(n.LastUpdate.Unix()),
Addresses: n.Addresses,
NodeID: n.PubKey,
NodeID: n.PubKeyBytes,
Features: n.Features.RawFeatureVector,
RGBColor: n.Color,
Alias: alias,
}
}, nil
}
// 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
// well.
if chanInfo.AuthProof != nil {
chanAnn, e1Ann, e2Ann := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2)
chanAnn, e1Ann, e2Ann, err := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2,
)
if err != nil {
return err
}
announceMessages = append(announceMessages, chanAnn)
if e1Ann != nil {
@ -272,7 +285,10 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// If this edge has a validated node
// announcement, then we'll send that as well.
if e1.Node.HaveNodeAnnouncement {
nodeAnn := makeNodeAnn(e1.Node)
nodeAnn, err := makeNodeAnn(e1.Node)
if err != nil {
return err
}
announceMessages = append(
announceMessages, nodeAnn,
)
@ -285,7 +301,10 @@ func (d *AuthenticatedGossiper) SynchronizeNode(pub *btcec.PublicKey) error {
// If this edge has a validated node
// announcement, then we'll send that as well.
if e2.Node.HaveNodeAnnouncement {
nodeAnn := makeNodeAnn(e2.Node)
nodeAnn, err := makeNodeAnn(e2.Node)
if err != nil {
return err
}
announceMessages = append(
announceMessages, nodeAnn,
)
@ -588,7 +607,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
// NodeID to create the corresponding Vertex.
case *lnwire.NodeAnnouncement:
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
// updates, as they also carry a timestamp.
@ -875,6 +894,13 @@ func (d *AuthenticatedGossiper) networkHandler() {
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
// slot for this job opens up, this allow us to not
// 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
// 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
@ -1182,9 +1228,12 @@ func (d *AuthenticatedGossiper) processRejectedEdge(chanAnnMsg *lnwire.ChannelAn
// We'll then create then validate the new fully assembled
// announcement.
chanAnn, e1Ann, e2Ann := createChanAnnouncement(
chanAnn, e1Ann, e2Ann, err := createChanAnnouncement(
proof, chanInfo, e1, e2,
)
if err != nil {
return nil, err
}
err = ValidateChannelAnn(chanAnn)
if err != nil {
err := errors.Errorf("assembled channel announcement proof "+
@ -1265,9 +1314,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Addresses: msg.Addresses,
PubKey: msg.NodeID,
PubKeyBytes: msg.NodeID,
Alias: msg.Alias.String(),
AuthSig: msg.Signature,
AuthSigBytes: msg.Signature.ToSignatureBytes(),
Features: features,
Color: msg.RGBColor,
}
@ -1307,6 +1356,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
log.Error("Ignoring ChannelAnnouncement from "+
"chain=%v, gossiper on chain=%v", msg.ChainHash,
d.cfg.ChainHash)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil
}
@ -1338,6 +1390,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if err := ValidateChannelAnn(msg); err != nil {
err := errors.Errorf("unable to validate "+
"announcement: %v", err)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
log.Error(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
// gossiping with other nodes.
proof = &channeldb.ChannelAuthProof{
NodeSig1: msg.NodeSig1,
NodeSig2: msg.NodeSig2,
BitcoinSig1: msg.BitcoinSig1,
BitcoinSig2: msg.BitcoinSig2,
NodeSig1Bytes: msg.NodeSig1.ToSignatureBytes(),
NodeSig2Bytes: msg.NodeSig2.ToSignatureBytes(),
BitcoinSig1Bytes: msg.BitcoinSig1.ToSignatureBytes(),
BitcoinSig2Bytes: msg.BitcoinSig2.ToSignatureBytes(),
}
}
@ -1365,14 +1420,14 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
}
edge := &channeldb.ChannelEdgeInfo{
ChannelID: msg.ShortChannelID.ToUint64(),
ChainHash: msg.ChainHash,
NodeKey1: msg.NodeID1,
NodeKey2: msg.NodeID2,
BitcoinKey1: msg.BitcoinKey1,
BitcoinKey2: msg.BitcoinKey2,
AuthProof: proof,
Features: featureBuf.Bytes(),
ChannelID: msg.ShortChannelID.ToUint64(),
ChainHash: msg.ChainHash,
NodeKey1Bytes: msg.NodeID1,
NodeKey2Bytes: msg.NodeID2,
BitcoinKey1Bytes: msg.BitcoinKey1,
BitcoinKey2Bytes: msg.BitcoinKey2,
AuthProof: proof,
Features: featureBuf.Bytes(),
}
// 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.
anns, rErr := d.processRejectedEdge(msg, proof)
if rErr != nil {
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
nMsg.err <- rErr
return nil
}
@ -1499,6 +1557,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
log.Error("Ignoring ChannelUpdate from "+
"chain=%v, gossiper on chain=%v", msg.ChainHash,
d.cfg.ChainHash)
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil
}
@ -1560,7 +1621,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
d.prematureChannelUpdates[shortChanID],
nMsg)
d.pChanUpdMtx.Unlock()
log.Infof("Got ChannelUpdate for edge not "+
log.Debugf("Got ChannelUpdate for edge not "+
"found in graph(shortChanID=%v), "+
"saving for reprocessing later",
shortChanID)
@ -1572,6 +1633,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
shortChanID, err)
log.Error(err)
nMsg.err <- err
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
return nil
}
}
@ -1582,9 +1647,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
var pubKey *btcec.PublicKey
switch {
case msg.Flags&lnwire.ChanUpdateDirection == 0:
pubKey = chanInfo.NodeKey1
pubKey, _ = chanInfo.NodeKey1()
case msg.Flags&lnwire.ChanUpdateDirection == 1:
pubKey = chanInfo.NodeKey2
pubKey, _ = chanInfo.NodeKey2()
}
// Validate the channel announcement with the expected public
@ -1601,7 +1666,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
}
update := &channeldb.ChannelEdgePolicy{
Signature: msg.Signature,
SigBytes: msg.Signature.ToSignatureBytes(),
ChannelID: shortChanID,
LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Flags: msg.Flags,
@ -1615,6 +1680,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if routing.IsError(err, routing.ErrOutdated, routing.ErrIgnored) {
log.Debug(err)
} else {
d.rejectMtx.Lock()
d.recentRejects[msg.ShortChannelID.ToUint64()] = struct{}{}
d.rejectMtx.Unlock()
log.Error(err)
}
@ -1632,9 +1700,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
var remotePeer *btcec.PublicKey
switch {
case msg.Flags&lnwire.ChanUpdateDirection == 0:
remotePeer = chanInfo.NodeKey2
remotePeer, _ = chanInfo.NodeKey2()
case msg.Flags&lnwire.ChanUpdateDirection == 1:
remotePeer = chanInfo.NodeKey1
remotePeer, _ = chanInfo.NodeKey1()
}
// Send ChannelUpdate directly to remotePeer.
@ -1726,9 +1794,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
}
isFirstNode := bytes.Equal(nMsg.peer.SerializeCompressed(),
chanInfo.NodeKey1.SerializeCompressed())
chanInfo.NodeKey1Bytes[:])
isSecondNode := bytes.Equal(nMsg.peer.SerializeCompressed(),
chanInfo.NodeKey2.SerializeCompressed())
chanInfo.NodeKey2Bytes[:])
// Ensure that channel that was retrieved belongs to the peer
// which sent the proof announcement.
@ -1748,9 +1816,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
if !nMsg.isRemote {
var remotePeer *btcec.PublicKey
if isFirstNode {
remotePeer = chanInfo.NodeKey2
remotePeer, _ = chanInfo.NodeKey2()
} else {
remotePeer = chanInfo.NodeKey1
remotePeer, _ = chanInfo.NodeKey1()
}
// Since the remote peer might not be online
// we'll call a method that will attempt to
@ -1786,9 +1854,14 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
msg.ChannelID,
peerID)
chanAnn, _, _ := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2)
err := d.cfg.SendToPeer(nMsg.peer, chanAnn)
chanAnn, _, _, err := createChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2,
)
if err != nil {
log.Errorf("unable to gen ann: %v", err)
return
}
err = d.cfg.SendToPeer(nMsg.peer, chanAnn)
if err != nil {
log.Errorf("Failed sending "+
"full proof to "+
@ -1846,17 +1919,22 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []n
// validate it shortly below.
var dbProof channeldb.ChannelAuthProof
if isFirstNode {
dbProof.NodeSig1 = msg.NodeSignature
dbProof.NodeSig2 = oppositeProof.NodeSignature
dbProof.BitcoinSig1 = msg.BitcoinSignature
dbProof.BitcoinSig2 = oppositeProof.BitcoinSignature
dbProof.NodeSig1Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = msg.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
} else {
dbProof.NodeSig1 = oppositeProof.NodeSignature
dbProof.NodeSig2 = msg.NodeSignature
dbProof.BitcoinSig1 = oppositeProof.BitcoinSignature
dbProof.BitcoinSig2 = msg.BitcoinSignature
dbProof.NodeSig1Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
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
// full channel announcement proof.
@ -2017,6 +2095,8 @@ func (d *AuthenticatedGossiper) sendAnnSigReliably(
func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
edge *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate, error) {
var err error
// Make sure timestamp is always increased, such that our update
// gets propagated.
timestamp := time.Now().Unix()
@ -2025,7 +2105,6 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
}
edge.LastUpdate = time.Unix(timestamp, 0)
chanUpdate := &lnwire.ChannelUpdate{
Signature: edge.Signature,
ChainHash: info.ChainHash,
ShortChannelID: lnwire.NewShortChanIDFromInt(edge.ChannelID),
Timestamp: uint32(timestamp),
@ -2035,6 +2114,10 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
BaseFee: uint32(edge.FeeBaseMSat),
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
// 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
// in the backing slice.
edge.Signature = sig
chanUpdate.Signature = sig
edge.SigBytes = sig.Serialize()
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
// 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.
edge.Node.PubKey.Curve = nil
if err := d.cfg.Router.UpdateEdge(edge); err != nil {
return nil, nil, err
}
@ -2069,17 +2154,37 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
if info.AuthProof != nil {
chanID := lnwire.NewShortChanIDFromInt(info.ChannelID)
chanAnn = &lnwire.ChannelAnnouncement{
NodeSig1: info.AuthProof.NodeSig1,
NodeSig2: info.AuthProof.NodeSig2,
ShortChannelID: chanID,
BitcoinSig1: info.AuthProof.BitcoinSig1,
BitcoinSig2: info.AuthProof.BitcoinSig2,
NodeID1: info.NodeKey1,
NodeID2: info.NodeKey2,
NodeID1: info.NodeKey1Bytes,
NodeID2: info.NodeKey2Bytes,
ChainHash: info.ChainHash,
BitcoinKey1: info.BitcoinKey1,
BitcoinKey1: info.BitcoinKey1Bytes,
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 {
return nil, err
}
batch.localChanAnn.BitcoinSig1 = nil
batch.localChanAnn.BitcoinSig2 = nil
batch.localChanAnn.NodeSig1 = nil
batch.localChanAnn.NodeSig2 = nil
batch.chanUpdAnn1, err = createUpdateAnnouncement(
blockHeight, 0, nodeKeyPriv1, timestamp,
@ -342,13 +338,18 @@ func createNodeAnnouncement(priv *btcec.PrivateKey,
a := &lnwire.NodeAnnouncement{
Timestamp: timestamp,
Addresses: testAddrs,
NodeID: priv.PubKey(),
Alias: alias,
Features: testFeatures,
}
copy(a.NodeID[:], priv.PubKey().SerializeCompressed())
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 {
return nil, err
}
@ -376,7 +377,13 @@ func createUpdateAnnouncement(blockHeight uint32, flags lnwire.ChanUpdateFlag,
pub := nodeKey.PubKey()
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
}
@ -392,34 +399,54 @@ func createRemoteChannelAnnouncement(blockHeight uint32) (*lnwire.ChannelAnnounc
TxIndex: 0,
TxPosition: 0,
},
NodeID1: nodeKeyPub1,
NodeID2: nodeKeyPub2,
BitcoinKey1: bitcoinKeyPub1,
BitcoinKey2: bitcoinKeyPub2,
Features: testFeatures,
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()
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
}
pub = nodeKeyPriv2.PubKey()
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
}
pub = bitcoinKeyPriv1.PubKey()
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
}
pub = bitcoinKeyPriv2.PubKey()
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
}
@ -521,8 +548,10 @@ func TestProcessAnnouncement(t *testing.T) {
t.Fatalf("can't create node announcement: %v", err)
}
nodePub := nodeKeyPriv1.PubKey()
select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(na, na.NodeID):
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(na, nodePub):
case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed")
}
@ -532,7 +561,7 @@ func TestProcessAnnouncement(t *testing.T) {
select {
case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg)
assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded")
}
@ -550,7 +579,7 @@ func TestProcessAnnouncement(t *testing.T) {
}
select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ca, na.NodeID):
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ca, nodePub):
case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed")
}
@ -560,7 +589,7 @@ func TestProcessAnnouncement(t *testing.T) {
select {
case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg)
assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded")
}
@ -578,7 +607,7 @@ func TestProcessAnnouncement(t *testing.T) {
}
select {
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ua, na.NodeID):
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(ua, nodePub):
case <-time.After(2 * time.Second):
t.Fatal("remote announcement not processed")
}
@ -588,7 +617,7 @@ func TestProcessAnnouncement(t *testing.T) {
select {
case msg := <-ctx.broadcastedMessage:
assertSenderExistence(na.NodeID, msg)
assertSenderExistence(nodePub, msg)
case <-time.After(2 * trickleDelay):
t.Fatal("announcement wasn't proceeded")
}
@ -612,11 +641,13 @@ func TestPrematureAnnouncement(t *testing.T) {
}
defer cleanup()
na, err := createNodeAnnouncement(nodeKeyPriv1, timestamp)
_, err = createNodeAnnouncement(nodeKeyPriv1, timestamp)
if err != nil {
t.Fatalf("can't create node announcement: %v", err)
}
nodePub := nodeKeyPriv1.PubKey()
// Pretending that we receive the valid channel announcement from
// remote side, but block height of this announcement is greater than
// highest know to us, for that reason it should be added to the
@ -627,7 +658,7 @@ func TestPrematureAnnouncement(t *testing.T) {
}
select {
case <-ctx.gossiper.ProcessRemoteAnnouncement(ca, na.NodeID):
case <-ctx.gossiper.ProcessRemoteAnnouncement(ca, nodePub):
t.Fatal("announcement was proceeded")
case <-time.After(100 * time.Millisecond):
}
@ -646,7 +677,7 @@ func TestPrematureAnnouncement(t *testing.T) {
}
select {
case <-ctx.gossiper.ProcessRemoteAnnouncement(ua, na.NodeID):
case <-ctx.gossiper.ProcessRemoteAnnouncement(ua, nodePub):
t.Fatal("announcement was proceeded")
case <-time.After(100 * time.Millisecond):
}
@ -709,8 +740,14 @@ func TestSignatureAnnouncementLocalFirst(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// between two nodes.
@ -865,8 +902,14 @@ func TestOrphanSignatureAnnouncement(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// 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)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// between two nodes.
@ -1203,8 +1252,14 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// between two nodes.
@ -1422,8 +1477,14 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// between two nodes.
@ -1819,8 +1880,14 @@ func TestReceiveRemoteChannelUpdateFirst(t *testing.T) {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
localKey, err := btcec.ParsePubKey(batch.nodeAnn1.NodeID[:], btcec.S256())
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
// before we have been able to process our own ChannelAnnouncement and

@ -16,24 +16,46 @@ import (
func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
chanInfo *channeldb.ChannelEdgeInfo,
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
// authentication chanProof, we'll create re-create the original
// authenticated channel announcement.
chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
chanAnn := &lnwire.ChannelAnnouncement{
NodeSig1: chanProof.NodeSig1,
NodeSig2: chanProof.NodeSig2,
ShortChannelID: chanID,
BitcoinSig1: chanProof.BitcoinSig1,
BitcoinSig2: chanProof.BitcoinSig2,
NodeID1: chanInfo.NodeKey1,
NodeID2: chanInfo.NodeKey2,
NodeID1: chanInfo.NodeKey1Bytes,
NodeID2: chanInfo.NodeKey2Bytes,
ChainHash: chanInfo.ChainHash,
BitcoinKey1: chanInfo.BitcoinKey1,
BitcoinKey1: chanInfo.BitcoinKey1Bytes,
BitcoinKey2: chanInfo.BitcoinKey2Bytes,
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
@ -46,7 +68,6 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
var edge1Ann, edge2Ann *lnwire.ChannelUpdate
if e1 != nil {
edge1Ann = &lnwire.ChannelUpdate{
Signature: e1.Signature,
ChainHash: chanInfo.ChainHash,
ShortChannelID: chanID,
Timestamp: uint32(e1.LastUpdate.Unix()),
@ -56,10 +77,13 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
BaseFee: uint32(e1.FeeBaseMSat),
FeeRate: uint32(e1.FeeProportionalMillionths),
}
edge1Ann.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes)
if err != nil {
return nil, nil, nil, err
}
}
if e2 != nil {
edge2Ann = &lnwire.ChannelUpdate{
Signature: e2.Signature,
ChainHash: chanInfo.ChainHash,
ShortChannelID: chanID,
Timestamp: uint32(e2.LastUpdate.Unix()),
@ -69,9 +93,13 @@ func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
BaseFee: uint32(e2.FeeBaseMSat),
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

@ -1062,14 +1062,6 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
// the commitment transaction to the remote peer.
outPoint := resCtx.reservation.FundingOutpoint()
_, 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
// properly synchronize with the writeHandler goroutine, we add a new
@ -1095,7 +1087,14 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fundingCreated := &lnwire.FundingCreated{
PendingChannelID: pendingChanID,
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)
if err != nil {
@ -1148,7 +1147,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// funding transaction will broadcast after our next message.
// CompleteReservationSingle will also mark the channel as 'IsPending'
// in the database.
commitSig := fmsg.msg.CommitSig.Serialize()
commitSig := fmsg.msg.CommitSig.ToSignatureBytes()
completeChan, err := resCtx.reservation.CompleteReservationSingle(
&fundingOut, commitSig)
if err != nil {
@ -1191,11 +1190,8 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// With their signature for our version of the commitment transaction
// 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()
ourCommitSig, err := btcec.ParseSignature(sig, btcec.S256())
ourCommitSig, err := lnwire.NewSigFromRawSignature(sig)
if err != nil {
fndgLog.Errorf("unable to parse signature: %v", err)
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
// transaction. We'll verify the signature for validity, then commit
// 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)
if err != nil {
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()
remoteBytes := remotePubKey.SerializeCompressed()
if bytes.Compare(selfBytes, remoteBytes) == -1 {
chanAnn.NodeID1 = localPubKey
chanAnn.NodeID2 = remotePubKey
chanAnn.BitcoinKey1 = localFundingKey
chanAnn.BitcoinKey2 = remoteFundingKey
copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed())
copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed())
copy(chanAnn.BitcoinKey1[:], localFundingKey.SerializeCompressed())
copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed())
// If we're the first node then update the chanFlags to
// indicate the "direction" of the update.
chanFlags = 0
} else {
chanAnn.NodeID1 = remotePubKey
chanAnn.NodeID2 = localPubKey
chanAnn.BitcoinKey1 = remoteFundingKey
chanAnn.BitcoinKey2 = localFundingKey
copy(chanAnn.NodeID1[:], remotePubKey.SerializeCompressed())
copy(chanAnn.NodeID2[:], localPubKey.SerializeCompressed())
copy(chanAnn.BitcoinKey1[:], remoteFundingKey.SerializeCompressed())
copy(chanAnn.BitcoinKey2[:], localFundingKey.SerializeCompressed())
// If we're the second node then update the chanFlags to
// indicate the "direction" of the update.
@ -2171,7 +2167,12 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey *btcec.Pu
if err != nil {
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 {
return nil, errors.Errorf("unable to generate channel "+
"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
// allow them to reconstruct the full channel announcement.
proof := &lnwire.AnnounceSignatures{
ChannelID: chanID,
ShortChannelID: shortChanID,
NodeSignature: nodeSig,
BitcoinSignature: bitcoinSig,
ChannelID: chanID,
ShortChannelID: shortChanID,
}
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{

@ -5,6 +5,7 @@ package main
import (
"fmt"
"io/ioutil"
"math/big"
"net"
"os"
"path/filepath"
@ -79,6 +80,13 @@ var (
IdentityKey: bobPubKey,
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 {
@ -217,7 +225,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
Notifier: chainNotifier,
FeeEstimator: estimator,
SignMessage: func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) {
return nil, nil
return testSig, nil
},
SendAnnouncement: func(msg lnwire.Message) error {
select {
@ -319,7 +327,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
FeeEstimator: oldCfg.FeeEstimator,
SignMessage: func(pubKey *btcec.PublicKey,
msg []byte) (*btcec.Signature, error) {
return nil, nil
return testSig, nil
},
SendAnnouncement: func(msg lnwire.Message) error {
select {

@ -57,13 +57,6 @@ func messageToString(msg lnwire.Message) string {
switch m := msg.(type) {
case *lnwire.RevokeAndAck:
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:
m.FundingKey.Curve = nil
m.RevocationPoint.Curve = nil

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

@ -2557,8 +2557,8 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
// new commitment to the remote party. The commit diff returned contains all
// information necessary for retransmission.
func (lc *LightningChannel) createCommitDiff(
newCommit *commitment, commitSig *btcec.Signature,
htlcSigs []*btcec.Signature) (*channeldb.CommitDiff, error) {
newCommit *commitment, commitSig lnwire.Sig,
htlcSigs []lnwire.Sig) (*channeldb.CommitDiff, error) {
// 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
@ -2673,10 +2673,15 @@ func (lc *LightningChannel) createCommitDiff(
// 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
// 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()
defer lc.Unlock()
var (
sig lnwire.Sig
htlcSigs []lnwire.Sig
)
// 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
// 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
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.
@ -2698,7 +2703,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
err := lc.validateCommitmentSanity(remoteACKedIndex,
lc.localUpdateLog.logIndex, false, true, true)
if err != nil {
return nil, nil, err
return sig, htlcSigs, err
}
// 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,
)
if err != nil {
return nil, nil, err
return sig, htlcSigs, err
}
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,
)
if err != nil {
return nil, nil, err
return sig, htlcSigs, err
}
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)
if err != nil {
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 {
close(cancelChan)
return nil, nil, err
return sig, htlcSigs, err
}
// 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
// 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 {
select {
case jobResp := <-htlcSigJob.resp:
@ -2780,12 +2785,12 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
// active jobs.
if jobResp.err != nil {
close(cancelChan)
return nil, nil, err
return sig, htlcSigs, err
}
htlcSigs = append(htlcSigs, jobResp.sig)
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.
commitDiff, err := lc.createCommitDiff(newCommitView, sig, htlcSigs)
if err != nil {
return nil, nil, err
return sig, htlcSigs, err
}
if lc.channelState.AppendRemoteCommitChain(commitDiff); err != nil {
return nil, nil, err
return sig, htlcSigs, err
}
// 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
// directly into the pool of workers.
func genHtlcSigValidationJobs(localCommitmentView *commitment,
keyRing *CommitmentKeyRing, htlcSigs []*btcec.Signature,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) []verifyJob {
keyRing *CommitmentKeyRing, htlcSigs []lnwire.Sig,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) ([]verifyJob, error) {
// If this new commitment state doesn't have any HTLC's that are to be
// signed, then we'll return a nil slice.
if len(htlcSigs) == 0 {
return nil
return nil, nil
}
txHash := localCommitmentView.txn.TxHash()
@ -3154,7 +3159,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
// to validate each signature within the worker pool.
i := 0
for index := range localCommitmentView.txn.TxOut {
var sigHash func() ([]byte, error)
var (
sigHash func() ([]byte, error)
sig *btcec.Signature
err error
)
outputIndex := int32(index)
switch {
@ -3197,7 +3206,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
// With the sighash generated, we'll also store the
// signature so it can be written to disk if this state
// 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
// 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
// signature so it can be written to disk if this state
// is valid.
htlc.sig = htlcSigs[i]
sig, err = htlcSigs[i].ToSignature()
if err != nil {
return nil, err
}
htlc.sig = sig
default:
continue
@ -3247,14 +3264,14 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
verifyJobs = append(verifyJobs, verifyJob{
pubKey: keyRing.RemoteHtlcKey,
sig: htlcSigs[i],
sig: sig,
sigHash: sigHash,
})
i++
}
return verifyJobs
return verifyJobs, nil
}
// 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
// state, then this newly added commitment becomes our current accepted channel
// state.
func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
htlcSigs []*btcec.Signature) error {
func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig,
htlcSigs []lnwire.Sig) error {
lc.Lock()
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
// pool to verify each of the HTLc signatures presented. Once
// generated, we'll submit these jobs to the worker pool.
verifyJobs := genHtlcSigValidationJobs(localCommitmentView,
keyRing, htlcSigs, lc.localChanCfg, lc.remoteChanCfg)
verifyJobs, err := genHtlcSigValidationJobs(
localCommitmentView, keyRing, htlcSigs, lc.localChanCfg,
lc.remoteChanCfg,
)
if err != nil {
return err
}
cancelChan := make(chan struct{})
verifyResps := lc.sigPool.SubmitVerifyBatch(verifyJobs, cancelChan)
@ -3379,7 +3402,11 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
Y: lc.remoteChanCfg.MultiSigKey.Y,
Curve: btcec.S256(),
}
if !commitSig.Verify(sigHash, &verifyKey) {
cSig, err := commitSig.ToSignature()
if err != nil {
return err
}
if !cSig.Verify(sigHash, &verifyKey) {
close(cancelChan)
// If we fail to validate their commitment signature, we'll
@ -3390,7 +3417,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
localCommitTx.Serialize(&txBytes)
return &InvalidCommitSigError{
commitHeight: nextHeight,
commitSig: commitSig.Serialize(),
commitSig: commitSig.ToSignatureBytes(),
sigHash: sigHash,
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
// our local commitment chain.
localCommitmentView.sig = commitSig.Serialize()
localCommitmentView.sig = commitSig.ToSignatureBytes()
lc.localCommitChain.addCommitment(localCommitmentView)
// If we are not channel initiator, then the commitment just received

@ -4,7 +4,6 @@ import (
"bytes"
"crypto/sha256"
"io/ioutil"
"math/big"
"math/rand"
"os"
"reflect"
@ -2768,20 +2767,20 @@ func TestChanSyncOweCommitment(t *testing.T) {
t.Fatalf("expected a CommitSig message, instead have %v",
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",
aliceSig.Serialize(), commitSigMsg.CommitSig.Serialize())
aliceSig, commitSigMsg.CommitSig)
}
if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(aliceHtlcSigs), len(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: "+
"expected %x got %x",
aliceHtlcSigs[i].Serialize(),
htlcSig.Serialize())
aliceHtlcSigs[i],
htlcSig)
}
}
}
@ -3228,20 +3227,19 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
t.Fatalf("expected bob to re-send commit sig, instead sending: %v",
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",
bobSig.Serialize(), bobReCommitSigMsg.CommitSig.Serialize())
bobSig, bobReCommitSigMsg.CommitSig)
}
if len(bobReCommitSigMsg.HtlcSigs) != len(bobHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(bobHtlcSigs), len(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: "+
"expected %x got %x",
bobHtlcSigs[i].Serialize(),
htlcSig.Serialize())
bobHtlcSigs[i], htlcSig)
}
}
}
@ -3426,21 +3424,20 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
t.Fatalf("revocation msgs don't match: expected %v, got %v",
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",
bobSigMsg.CommitSig.Serialize(),
bobReCommitSigMsg.CommitSig.Serialize())
bobSigMsg.CommitSig,
bobReCommitSigMsg.CommitSig)
}
if len(bobReCommitSigMsg.HtlcSigs) != len(bobSigMsg.HtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(bobSigMsg.HtlcSigs), len(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: "+
"expected %x got %x",
bobSigMsg.HtlcSigs[i].Serialize(),
htlcSig.Serialize())
bobSigMsg.HtlcSigs[i], htlcSig)
}
}
@ -3598,20 +3595,19 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
t.Fatalf("expected a CommitSig message, instead have %v",
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",
aliceSig.Serialize(), commitSigMsg.CommitSig.Serialize())
aliceSig, commitSigMsg.CommitSig)
}
if len(commitSigMsg.HtlcSigs) != len(aliceHtlcSigs) {
t.Fatalf("wrong number of htlc sigs: expected %v, got %v",
len(aliceHtlcSigs), len(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: "+
"expected %x got %x",
aliceHtlcSigs[i].Serialize(),
htlcSig.Serialize())
aliceHtlcSigs[i], htlcSig)
}
}
@ -4127,7 +4123,7 @@ func TestInvalidCommitSigError(t *testing.T) {
// Before the signature gets to Bob, we'll mutate it, such that the
// 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.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)

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

@ -1,10 +1,6 @@
package lnwire
import (
"io"
"github.com/roasbeef/btcd/btcec"
)
import "io"
// AnnounceSignatures this is a direct message between two endpoints of a
// 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
// channel message, by this signature we proof that we possess of the
// 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
// public key, by this signature we proof that we possess of the
// bitcoin key and and creating the reverse reference bitcoin_key ->
// node_key.
BitcoinSignature *btcec.Signature
BitcoinSignature Sig
}
// A compile time check to ensure AnnounceSignatures implements the

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

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

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

@ -1,10 +1,6 @@
package lnwire
import (
"io"
"github.com/roasbeef/btcd/btcec"
)
import "io"
// 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
@ -26,7 +22,7 @@ type CommitSig struct {
// If initiating a new commitment state, this signature should ONLY
// cover all of the sending party's pending log updates, and the log
// 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
// 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
// should be signed, for each incoming HTLC the HTLC timeout
// transaction should be signed.
HtlcSigs []*btcec.Signature
HtlcSigs []Sig
}
// NewCommitSig creates a new empty CommitSig message.

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

@ -1,10 +1,6 @@
package lnwire
import (
"io"
"github.com/roasbeef/btcd/btcec"
)
import "io"
// FundingSigned is sent from Bob (the responder) to Alice (the initiator)
// 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
// transaction.
CommitSig *btcec.Signature
CommitSig Sig
}
// 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 {
return err
}
case []*btcec.Signature:
case []Sig:
var b [2]byte
numSigs := uint16(len(e))
binary.BigEndian.PutUint16(b[:], numSigs)
@ -159,18 +159,9 @@ func writeElement(w io.Writer, element interface{}) error {
return err
}
}
case *btcec.Signature:
if e == nil {
return fmt.Errorf("cannot write nil signature")
}
var b [64]byte
err := SerializeSigToWire(&b, e)
if err != nil {
return err
}
case Sig:
// Write buffer
if _, err = w.Write(b[:]); err != nil {
if _, err := w.Write(e[:]); err != nil {
return err
}
case PingPayload:
@ -210,6 +201,10 @@ func writeElement(w io.Writer, element interface{}) error {
return err
}
if _, err := w.Write(e[:]); err != nil {
return err
}
case [33]byte:
if _, err := w.Write(e[:]); err != nil {
return err
}
@ -469,16 +464,16 @@ func readElement(r io.Reader, element interface{}) error {
*e = f
case *[]*btcec.Signature:
case *[]Sig:
var l [2]byte
if _, err := io.ReadFull(r, l[:]); err != nil {
return err
}
numSigs := binary.BigEndian.Uint16(l[:])
var sigs []*btcec.Signature
var sigs []Sig
if numSigs > 0 {
sigs = make([]*btcec.Signature, numSigs)
sigs = make([]Sig, numSigs)
for i := 0; i < int(numSigs); i++ {
if err := readElement(r, &sigs[i]); err != nil {
return err
@ -488,13 +483,8 @@ func readElement(r io.Reader, element interface{}) error {
*e = sigs
case **btcec.Signature:
var b [64]byte
if _, err := io.ReadFull(r, b[:]); err != nil {
return err
}
err = DeserializeSigFromWire(e, b)
if err != nil {
case *Sig:
if _, err := io.ReadFull(r, e[:]); err != nil {
return err
}
case *OpaqueReason:
@ -541,6 +531,10 @@ func readElement(r io.Reader, element interface{}) error {
if _, err := io.ReadFull(r, *e); err != nil {
return err
}
case *[33]byte:
if _, err := io.ReadFull(r, e[:]); err != nil {
return err
}
case []byte:
if _, err := io.ReadFull(r, e); err != nil {
return err

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

@ -7,8 +7,6 @@ import (
"io"
"net"
"unicode/utf8"
"github.com/roasbeef/btcd/btcec"
)
var (
@ -50,7 +48,7 @@ func (n NodeAlias) String() string {
// announcement via a signature using the advertised node pubkey.
type NodeAnnouncement struct {
// 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 *RawFeatureVector
@ -59,7 +57,7 @@ type NodeAnnouncement struct {
Timestamp uint32
// 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
// graphs

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

@ -6,12 +6,16 @@ import (
"github.com/roasbeef/btcd/btcec"
)
// SerializeSigToWire serializes a *Signature to [64]byte in the format
// specified by the Lightning RFC.
func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
// Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized
// signatures on the wire, instead of DER encoded signatures. This type
// 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.
sig := e.Serialize()
// NewSigFromRawSignature returns a Sig from a Bitcoin raw signature encoded in
// 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
// 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]
// 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
// rLen in the case of a 33-byte 0-padded integer returned from
// Serialize() and rLen is used in calculating array indices for
// S. We can track this with additional variables, but it's more
// efficient to just check S first.
// We check S first because these code blocks decrement sLen and rLen
// in the case of a 33-byte 0-padded integer returned from Serialize()
// and rLen is used in calculating array indices for S. We can track
// this with additional variables, but it's more efficient to just
// check S first.
if sLen > 32 {
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")
}
sLen--
@ -42,7 +46,7 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
// Do the same for R as we did for S
if rLen > 32 {
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")
}
rLen--
@ -50,13 +54,33 @@ func SerializeSigToWire(b *[64]byte, e *btcec.Signature) error {
} else {
copy(b[32-rLen:], sig[4:4+rLen])
}
return nil
return b, nil
}
// DeserializeSigFromWire deserializes a *Signature from [64]byte in the format
// specified by the Lightning RFC.
func DeserializeSigFromWire(e **btcec.Signature, b [64]byte) error {
// NewSigFromSignature creates a new signature as used on the wire, from an
// existing btcec.Signature.
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
r := extractCanonicalPadding(b[0:32])
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[rLen+6:], s) // Copy S
// Parse the signature with strict checks.
sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256())
if err != nil {
return err
}
*e = sig
return nil
return sigBytes
}
// 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
// check for errors as well as check if the results are correct.
signatureSerializeDeserialize := func(e btcec.Signature) error {
var b [64]byte
err := SerializeSigToWire(&b, &e)
sig, err := NewSigFromSignature(&e)
if err != nil {
return err
}
var e2 *btcec.Signature
err = DeserializeSigFromWire(&e2, b)
e2, err := sig.ToSignature()
if err != nil {
return err
}
if e.R.Cmp(e2.R) != 0 {
return fmt.Errorf("Pre/post-serialize Rs don't match"+
": %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
// particular channel.
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
} else {
selfPolicy = p2
@ -900,8 +902,7 @@ func messageSummary(msg lnwire.Message) string {
case *lnwire.NodeAnnouncement:
return fmt.Sprintf("node=%x, update_time=%v",
msg.NodeID.SerializeCompressed(),
time.Unix(int64(msg.Timestamp), 0))
msg.NodeID, time.Unix(int64(msg.Timestamp), 0))
case *lnwire.Ping:
// No summary.
@ -957,13 +958,6 @@ func (p *peer) logWireMessage(msg lnwire.Message, read bool) {
}
case *lnwire.RevokeAndAck:
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:
m.FundingKey.Curve = nil
m.RevocationPoint.Curve = nil
@ -1774,16 +1768,17 @@ func createGetLastUpdate(router *routing.ChannelRouter,
"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
if bytes.Compare(edge1.Node.PubKey.SerializeCompressed(),
pubKey[:]) == 0 {
if bytes.Equal(edge1.Node.PubKeyBytes[:], pubKey[:]) {
local = edge2
} else {
local = edge1
}
update := &lnwire.ChannelUpdate{
Signature: local.Signature,
ChainHash: info.ChainHash,
ShortChannelID: lnwire.NewShortChanIDFromInt(local.ChannelID),
Timestamp: uint32(local.LastUpdate.Unix()),
@ -1793,6 +1788,10 @@ func createGetLastUpdate(router *routing.ChannelRouter,
BaseFee: uint32(local.FeeBaseMSat),
FeeRate: uint32(local.FeeProportionalMillionths),
}
update.Signature, err = lnwire.NewSigFromRawSignature(local.SigBytes)
if err != nil {
return nil, err
}
hswcLog.Debugf("Sending latest channel_update: %v",
spew.Sdump(update))

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

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

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

@ -1,6 +1,7 @@
package routing
import (
"bytes"
"encoding/binary"
"fmt"
"math"
@ -148,7 +149,7 @@ type Route struct {
// target node is not found in the route, then false is returned.
func (r *Route) nextHopVertex(n *btcec.PublicKey) (Vertex, bool) {
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
@ -259,7 +260,7 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
// First, we'll update both the node and channel index, to
// indicate that this Vertex, and outgoing channel link are
// present within this route.
v := NewVertex(edge.Node.PubKey)
v := Vertex(edge.Node.PubKeyBytes)
route.nodeIndex[v] = struct{}{}
route.chanIndex[edge.ChannelID] = struct{}{}
@ -314,7 +315,6 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
AmtToForward: amtToForward,
Fee: fee,
}
edge.Node.PubKey.Curve = nil
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
// our prev hop mapping.
for _, hop := range route.Hops {
vertex := NewVertex(hop.Channel.Node.PubKey)
vertex := Vertex(hop.Channel.Node.PubKeyBytes)
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.
type edgeWithPrev struct {
edge *ChannelHop
prevNode *btcec.PublicKey
prevNode [33]byte
}
// 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 {
// TODO(roasbeef): with larger graph can just use disk seeks
// with a visited map
distance[NewVertex(node.PubKey)] = nodeWithDist{
distance[Vertex(node.PubKeyBytes)] = nodeWithDist{
dist: infinity,
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
// distance map with with a distance of 0. This indicates our starting
// point in the graph traversal.
sourceVertex := NewVertex(sourceNode.PubKey)
sourceVertex := Vertex(sourceNode.PubKeyBytes)
distance[sourceVertex] = nodeWithDist{
dist: 0,
node: sourceNode,
@ -465,6 +465,8 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph,
// heap.
heap.Push(&nodeHeap, distance[sourceVertex])
targetBytes := target.SerializeCompressed()
// 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`.
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
// edges), then we're done here and can exit the graph
// traversal early.
if bestNode.PubKey.IsEqual(target) {
if bytes.Equal(bestNode.PubKeyBytes[:], targetBytes) {
break
}
// Now that we've found the next potential step to take we'll
// examine all the outgoing edge (channels) from this node to
// further our graph traversal.
pivot := NewVertex(bestNode.PubKey)
pivot := Vertex(bestNode.PubKeyBytes)
err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx,
edgeInfo *channeldb.ChannelEdgeInfo,
outEdge, inEdge *channeldb.ChannelEdgePolicy) error {
v := NewVertex(outEdge.Node.PubKey)
v := Vertex(outEdge.Node.PubKeyBytes)
// If the outgoing edge is currently disabled, then
// 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,
Capacity: edgeInfo.Capacity,
},
prevNode: bestNode.PubKey,
prevNode: bestNode.PubKeyBytes,
}
// 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
// within the prevHop map.
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
@ -648,8 +649,6 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph,
shortestPaths = append(shortestPaths, firstPath)
source.PubKey.Curve = nil
// While we still have candidate paths to explore we'll keep exploring
// the sub-graphs created to find the next k-th shortest path.
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
// aren't the current spur node from the graph.
for _, hop := range rootPath {
node := hop.Node.PubKey
if node.IsEqual(spurNode.PubKey) {
node := hop.Node.PubKeyBytes
if node == spurNode.PubKeyBytes {
continue
}
ignoredVertexes[NewVertex(node)] = struct{}{}
ignoredVertexes[Vertex(node)] = struct{}{}
}
// With the edges that are part of our root path, and

@ -53,10 +53,10 @@ var (
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
testAuthProof = channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
}
)
@ -165,20 +165,16 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
if err != nil {
return nil, nil, nil, err
}
pub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
if err != nil {
return nil, nil, nil, err
}
dbNode := &channeldb.LightningNode{
HaveNodeAnnouncement: true,
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Now(),
Addresses: testAddrs,
PubKey: pub,
Alias: node.Alias,
Features: testFeatures,
}
copy(dbNode.PubKeyBytes[:], pubBytes)
// We require all aliases within the graph to be unique for our
// tests.
@ -187,6 +183,11 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
"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
// alias map for easy lookup.
aliasMap[node.Alias] = pub
@ -228,19 +229,11 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
if err != nil {
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)
if err != nil {
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]
txidBytes, err := chainhash.NewHashFromStr(fundingTXID)
@ -256,21 +249,23 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
// nodes.
edgeInfo := channeldb.ChannelEdgeInfo{
ChannelID: edge.ChannelID,
NodeKey1: node1Pub,
NodeKey2: node2Pub,
BitcoinKey1: node1Pub,
BitcoinKey2: node2Pub,
AuthProof: &testAuthProof,
ChannelPoint: fundingPoint,
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)
if err != nil && err != channeldb.ErrEdgeAlreadyExist {
return nil, nil, nil, err
}
edgePolicy := &channeldb.ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
Flags: lnwire.ChanUpdateFlag(edge.Flags),
ChannelID: edge.ChannelID,
LastUpdate: time.Now(),
@ -300,7 +295,7 @@ func TestBasicGraphPathFinding(t *testing.T) {
if err != nil {
t.Fatalf("unable to fetch source node: %v", err)
}
sourceVertex := NewVertex(sourceNode.PubKey)
sourceVertex := Vertex(sourceNode.PubKeyBytes)
ignoredEdges := make(map[uint64]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.
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",
route.Hops[0].Channel.Node.Alias)
}
// 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",
route.Hops[0].Channel.Node.Alias)
}
@ -833,7 +832,7 @@ func TestPathFindSpecExample(t *testing.T) {
if err != nil {
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")
}

@ -130,7 +130,7 @@ type Config struct {
// 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
// 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)
// ChannelPruneExpiry is the duration used to determine if a channel
@ -237,6 +237,9 @@ type ChannelRouter struct {
// consistency between the various database accesses.
channelEdgeMtx *multimutex.Mutex
rejectMtx sync.RWMutex
rejectCache map[uint64]struct{}
sync.RWMutex
quit chan struct{}
@ -268,6 +271,7 @@ func New(cfg Config) (*ChannelRouter, error) {
channelEdgeMtx: multimutex.NewMutex(),
selfNode: selfNode,
routeCache: make(map[routeTuple][]*Route),
rejectCache: make(map[uint64]struct{}),
quit: make(chan struct{}),
}, nil
}
@ -504,6 +508,93 @@ func (r *ChannelRouter) syncGraphWithChain() error {
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
// this goroutine include answering queries related to the state of the
// 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
// for pruning.
case <-graphPruneTicker.C:
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.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
}
if err := r.pruneZombieChans(); err != nil {
log.Errorf("unable to prune zombies: %v", err)
}
// 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
// we do know about this node, check that this update brings
// 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 {
return errors.Errorf("unable to query for the "+
"existence of node: %v", err)
@ -822,7 +842,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
if !exists {
return newErrf(ErrIgnored, "Ignoring node announcement"+
" 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
@ -833,18 +853,27 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
lastUpdate.Equal(msg.LastUpdate) {
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 {
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",
msg.PubKey.SerializeCompressed())
log.Infof("Updated vertex data for node=%x", msg.PubKeyBytes)
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
// already know of this channel, if so, then we can exit early.
_, _, 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
// channel. If not found, add a partial node to the database,
// containing only the node keys.
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey1)
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey1Bytes)
if !exists {
node1 := &channeldb.LightningNode{
PubKey: msg.NodeKey1,
PubKeyBytes: msg.NodeKey1Bytes,
HaveNodeAnnouncement: false,
}
err := r.cfg.Graph.AddLightningNode(node1)
if err != nil {
return errors.Errorf("unable to add node %v to"+
" the graph: %v",
node1.PubKey.SerializeCompressed(), err)
" the graph: %v", node1.PubKeyBytes, err)
}
}
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey2)
_, exists, _ = r.cfg.Graph.HasLightningNode(msg.NodeKey2Bytes)
if !exists {
node2 := &channeldb.LightningNode{
PubKey: msg.NodeKey2,
PubKeyBytes: msg.NodeKey2Bytes,
HaveNodeAnnouncement: false,
}
err := r.cfg.Graph.AddLightningNode(node2)
if err != nil {
return errors.Errorf("unable to add node %v to"+
" the graph: %v",
node2.PubKey.SerializeCompressed(), err)
" the graph: %v", node2.PubKeyBytes, err)
}
}
@ -911,8 +938,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// edge bitcoin keys and channel value corresponds to the
// reality.
_, witnessOutput, err := lnwallet.GenFundingPkScript(
msg.BitcoinKey1.SerializeCompressed(),
msg.BitcoinKey2.SerializeCompressed(),
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
chanUtxo.Value,
)
if err != nil {
@ -942,8 +968,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
log.Infof("New channel discovered! Link "+
"connects %x and %x with ChannelPoint(%v): "+
"chan_id=%v, capacity=%v",
msg.NodeKey1.SerializeCompressed(),
msg.NodeKey2.SerializeCompressed(),
msg.NodeKey1Bytes, msg.NodeKey2Bytes,
fundingPoint, msg.ChannelID, msg.Capacity)
// 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:
// 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)
// 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
// 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
} else if !exists {
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
// factored in.
validRoutes := make([]*Route, 0, len(shortestPaths))
sourceVertex := NewVertex(r.selfNode.PubKey)
sourceVertex := Vertex(r.selfNode.PubKeyBytes)
for _, path := range shortestPaths {
// 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
@ -1289,10 +1325,14 @@ func generateSphinxPacket(route *Route, paymentHash []byte) ([]byte,
// We create a new instance of the public key to avoid possibly
// mutating the curve parameters, which are unset in a higher
// level in order to avoid spamming the logs.
nodePub, err := hop.Channel.Node.PubKey()
if err != nil {
return nil, nil, err
}
pub := btcec.PublicKey{
Curve: btcec.S256(),
X: hop.Channel.Node.PubKey.X,
Y: hop.Channel.Node.PubKey.Y,
X: nodePub.X,
Y: nodePub.Y,
}
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
// the payment. If this attempt fails, then we'll continue on
// 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,
circuit)
if sendError != nil {
@ -1693,7 +1733,7 @@ func (r *ChannelRouter) applyChannelUpdate(msg *lnwire.ChannelUpdate) error {
}
err := r.UpdateEdge(&channeldb.ChannelEdgePolicy{
Signature: msg.Signature,
SigBytes: msg.Signature.ToSignatureBytes(),
ChannelID: msg.ShortChannelID.ToUint64(),
LastUpdate: time.Unix(int64(msg.Timestamp), 0),
Flags: msg.Flags,

@ -42,7 +42,7 @@ func (c *testCtx) RestartRouter() error {
Graph: c.graph,
Chain: c.chain,
ChainView: c.chainView,
SendToSwitch: func(_ *btcec.PublicKey,
SendToSwitch: func(_ [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil
},
@ -117,8 +117,9 @@ func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func()
Graph: graph,
Chain: chain,
ChainView: chainView,
SendToSwitch: func(_ *btcec.PublicKey,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
SendToSwitch: func(_ [33]byte, _ *lnwire.UpdateAddHTLC,
_ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil
},
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
// first hop. This should force the router to instead take the
// 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) {
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{
ErrorSource: sourceNode.PubKey,
ErrorSource: pub,
// TODO(roasbeef): temp node failure should be?
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}
@ -301,21 +306,26 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
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
// indicating that the channel from roasbeef to luoji is not operable
// with an UnknownNextPeer.
//
// TODO(roasbeef): filtering should be intelligent enough so just not
// 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) {
if ctx.aliases["luoji"].IsEqual(n) {
if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
// We'll first simulate an error from the first
// outgoing link to simulate the channel from luo ji to
// roasbeef not having enough capacity.
return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey,
ErrorSource: sourcePub,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}
}
@ -323,7 +333,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Next, we'll create an error from satoshi to indicate
// that the luoji node is not longer online, which should
// 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{
ErrorSource: ctx.aliases["satoshi"],
FailureMessage: &lnwire.FailUnknownNextPeer{},
@ -353,12 +363,12 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Next, we'll modify the SendToSwitch method to indicate that luo ji
// wasn't originally online. This should also halt the send all
// 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) {
if ctx.aliases["luoji"].IsEqual(n) {
if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey,
ErrorSource: sourcePub,
FailureMessage: &lnwire.FailUnknownNextPeer{},
}
}
@ -380,14 +390,14 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Finally, we'll modify the SendToSwitch function to indicate that the
// 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) {
if ctx.aliases["luoji"].IsEqual(n) {
if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) {
// We'll first simulate an error from the first
// outgoing link to simulate the channel from luo ji to
// roasbeef not having enough capacity.
return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode.PubKey,
ErrorSource: sourcePub,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}
}
@ -457,13 +467,13 @@ func TestAddProof(t *testing.T) {
// After utxo was recreated adding the edge without the proof.
edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(),
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: nil,
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
AuthProof: nil,
}
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge); err != nil {
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)
}
pub := priv1.PubKey()
node := &channeldb.LightningNode{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
PubKey: copyPubKey(priv1.PubKey()),
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(node.PubKeyBytes[:], pub.SerializeCompressed())
err = ctx.router.AddNode(node)
if !IsError(err, ErrIgnored) {
@ -527,15 +538,21 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
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.
_, exists1, err := ctx.graph.HasLightningNode(priv1.PubKey())
_, exists1, err := ctx.graph.HasLightningNode(pub1)
if err != nil {
t.Fatalf("unable to query graph: %v", err)
}
if exists1 {
t.Fatalf("node already existed")
}
_, exists2, err := ctx.graph.HasLightningNode(priv2.PubKey())
_, exists2, err := ctx.graph.HasLightningNode(pub2)
if err != nil {
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)
edge := &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(),
NodeKey1: copyPubKey(priv1.PubKey()),
NodeKey2: copyPubKey(priv2.PubKey()),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
AuthProof: nil,
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: pub1,
NodeKey2Bytes: pub2,
BitcoinKey1Bytes: pub1,
BitcoinKey2Bytes: pub2,
AuthProof: nil,
}
if err := ctx.router.AddEdge(edge); err != nil {
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
// finding.
edgePolicy := &channeldb.ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID,
LastUpdate: time.Now(),
TimeLockDelta: 10,
@ -589,7 +606,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// Create edge in the other direction as well.
edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID,
LastUpdate: time.Now(),
TimeLockDelta: 10,
@ -605,14 +622,14 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// After adding the edge between the two previously unknown nodes, they
// should have been added to the graph.
_, exists1, err = ctx.graph.HasLightningNode(priv1.PubKey())
_, exists1, err = ctx.graph.HasLightningNode(pub1)
if err != nil {
t.Fatalf("unable to query graph: %v", err)
}
if !exists1 {
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 {
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)
edge = &channeldb.ChannelEdgeInfo{
ChannelID: chanID.ToUint64(),
NodeKey1: pubKey1,
NodeKey2: pubKey2,
BitcoinKey1: pubKey1,
BitcoinKey2: pubKey2,
AuthProof: nil,
ChannelID: chanID.ToUint64(),
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 {
t.Fatalf("unable to add edge to the channel graph: %v.", err)
}
edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID,
LastUpdate: time.Now(),
TimeLockDelta: 10,
@ -684,7 +701,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
}
edgePolicy = &channeldb.ChannelEdgePolicy{
Signature: testSig,
SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID,
LastUpdate: time.Now(),
TimeLockDelta: 10,
@ -716,12 +733,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
PubKey: copyPubKey(priv1.PubKey()),
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed())
if err := ctx.router.AddNode(n1); err != nil {
t.Fatalf("could not add node: %v", err)
@ -731,12 +748,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
PubKey: copyPubKey(priv2.PubKey()),
Color: color.RGBA{1, 2, 3, 0},
Alias: "node22",
AuthSig: testSig,
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(n2.PubKeyBytes[:], priv2.PubKey().SerializeCompressed())
if err := ctx.router.AddNode(n2); err != nil {
t.Fatalf("could not add node: %v", err)
@ -865,36 +882,36 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
}
edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1,
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
ChannelID: chanID1,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
}
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err)
}
edge2 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID2,
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
ChannelID: chanID2,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
}
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge2); err != nil {
t.Fatalf("unable to add edge: %v", err)
@ -940,7 +957,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
Graph: ctx.graph,
Chain: ctx.chain,
ChainView: ctx.chainView,
SendToSwitch: func(_ *btcec.PublicKey,
SendToSwitch: func(_ [33]byte,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
return [32]byte{}, nil
},
@ -1067,36 +1084,40 @@ func TestDisconnectedBlocks(t *testing.T) {
}
edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1,
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
ChannelID: chanID1,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
}
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err)
}
edge2 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID2,
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
ChannelID: chanID2,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
}
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge2); err != nil {
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)
}
edge1 := &channeldb.ChannelEdgeInfo{
ChannelID: chanID1.ToUint64(),
NodeKey1: copyPubKey(node1.PubKey),
NodeKey2: copyPubKey(node2.PubKey),
BitcoinKey1: copyPubKey(bitcoinKey1),
BitcoinKey2: copyPubKey(bitcoinKey2),
ChannelID: chanID1.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
AuthProof: &channeldb.ChannelAuthProof{
NodeSig1: testSig,
NodeSig2: testSig,
BitcoinSig1: testSig,
BitcoinSig2: testSig,
NodeSig1Bytes: testSig.Serialize(),
NodeSig2Bytes: testSig.Serialize(),
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
}
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.router.AddEdge(edge1); err != nil {
t.Fatalf("unable to add edge: %v", err)
}

@ -104,8 +104,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
v.chanAnnFinSignal[msg.ShortChannelID] = annFinCond
v.chanEdgeDependencies[msg.ShortChannelID] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeID1)] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeID2)] = annFinCond
v.nodeAnnDependencies[Vertex(msg.NodeID1)] = annFinCond
v.nodeAnnDependencies[Vertex(msg.NodeID2)] = annFinCond
}
case *channeldb.ChannelEdgeInfo:
@ -116,8 +116,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
v.chanAnnFinSignal[shortID] = annFinCond
v.chanEdgeDependencies[shortID] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeKey1)] = annFinCond
v.nodeAnnDependencies[NewVertex(msg.NodeKey2)] = annFinCond
v.nodeAnnDependencies[Vertex(msg.NodeKey1Bytes)] = annFinCond
v.nodeAnnDependencies[Vertex(msg.NodeKey2Bytes)] = annFinCond
}
// These other types don't have any dependants, so no further
@ -127,6 +127,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) {
case *lnwire.ChannelUpdate:
return
case *lnwire.NodeAnnouncement:
// TODO(roasbeef): node ann needs to wait on existing channel updates
return
case *channeldb.LightningNode:
return
@ -167,12 +168,12 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) {
shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
signal, ok = v.chanEdgeDependencies[shortID]
case *channeldb.LightningNode:
vertex := NewVertex(msg.PubKey)
vertex := Vertex(msg.PubKeyBytes)
signal, ok = v.nodeAnnDependencies[vertex]
case *lnwire.ChannelUpdate:
signal, ok = v.chanEdgeDependencies[msg.ShortChannelID]
case *lnwire.NodeAnnouncement:
vertex := NewVertex(msg.NodeID)
vertex := Vertex(msg.NodeID)
signal, ok = v.nodeAnnDependencies[vertex]
// 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
// finished executing and we can proceed.
case *channeldb.LightningNode:
delete(v.nodeAnnDependencies, NewVertex(msg.PubKey))
delete(v.nodeAnnDependencies, Vertex(msg.PubKeyBytes))
case *lnwire.NodeAnnouncement:
delete(v.nodeAnnDependencies, NewVertex(msg.NodeID))
delete(v.nodeAnnDependencies, Vertex(msg.NodeID))
case *lnwire.ChannelUpdate:
delete(v.chanEdgeDependencies, msg.ShortChannelID)
case *channeldb.ChannelEdgePolicy:

@ -535,11 +535,14 @@ func (r *rpcServer) VerifyMessage(ctx context.Context,
}
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
// channels signed the message.
// TODO(phlip9): Require valid nodes to have capital in active channels.
graph := r.server.chanDB.ChannelGraph()
_, active, err := graph.HasLightningNode(pubKey)
_, active, err := graph.HasLightningNode(pub)
if err != nil {
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))
for i, hop := range route.Hops {
hopPub := hop.Channel.Node.PubKey.SerializeCompressed()
copy(paymentPath[i][:], hopPub)
hopPub := hop.Channel.Node.PubKeyBytes
copy(paymentPath[i][:], hopPub[:])
}
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)
resp.Nodes = append(resp.Nodes, &lnrpc.LightningNode{
LastUpdate: uint32(node.LastUpdate.Unix()),
PubKey: hex.EncodeToString(node.PubKey.SerializeCompressed()),
PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
Addresses: nodeAddrs,
Alias: node.Alias,
Color: nodeColor,
@ -2455,8 +2458,8 @@ func marshalDbEdge(edgeInfo *channeldb.ChannelEdgeInfo,
ChanPoint: edgeInfo.ChannelPoint.String(),
// TODO(roasbeef): update should be on edge info itself
LastUpdate: uint32(lastUpdate),
Node1Pub: hex.EncodeToString(edgeInfo.NodeKey1.SerializeCompressed()),
Node2Pub: hex.EncodeToString(edgeInfo.NodeKey2.SerializeCompressed()),
Node1Pub: hex.EncodeToString(edgeInfo.NodeKey1Bytes[:]),
Node2Pub: hex.EncodeToString(edgeInfo.NodeKey2Bytes[:]),
Capacity: int64(edgeInfo.Capacity),
}

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

@ -327,8 +327,8 @@ func Decode(invoice string) (*Invoice, error) {
if err != nil {
return nil, err
}
var sigBytes [64]byte
copy(sigBytes[:], sigBase256[:64])
var sig lnwire.Sig
copy(sig[:], sigBase256[:64])
recoveryID := sigBase256[64]
// 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
// to verify the signature, if not do public key recovery.
if decodedInvoice.Destination != nil {
var signature *btcec.Signature
err := lnwire.DeserializeSigFromWire(&signature, sigBytes)
signature, err := sig.ToSignature()
if err != nil {
return nil, fmt.Errorf("unable to deserialize "+
"signature: %v", err)
@ -358,7 +357,7 @@ func Decode(invoice string) (*Invoice, error) {
}
} else {
headerByte := recoveryID + 27 + 4
compactSign := append([]byte{headerByte}, sigBytes[:]...)
compactSign := append([]byte{headerByte}, sig[:]...)
pubkey, _, err := btcec.RecoverCompact(btcec.S256(),
compactSign, hash)
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
// bytes encode the signature.
recoveryID := sign[0] - 27 - 4
var sigBytes [64]byte
copy(sigBytes[:], sign[1:])
var sig lnwire.Sig
copy(sig[:], sign[1:])
// If the pubkey field was explicitly set, it must be set to the pubkey
// used to create the signature.
if invoice.Destination != nil {
var signature *btcec.Signature
err = lnwire.DeserializeSigFromWire(&signature, sigBytes)
signature, err := sig.ToSignature()
if err != nil {
return "", fmt.Errorf("unable to deserialize "+
"signature: %v", err)
}
valid := signature.Verify(hash, invoice.Destination)
if !valid {
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.
signBase32, err := bech32.ConvertBits(append(sigBytes[:], recoveryID), 8, 5, true)
signBase32, err := bech32.ConvertBits(append(sig[:], recoveryID), 8, 5, true)
if err != nil {
return "", err
}