mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-26 21:46:37 +02:00
Merge pull request #8805 from breez/jssdwt-insert-edge-when-not-found
localchans: recreate missing edge if not found
This commit is contained in:
31
routing/localchans/log.go
Normal file
31
routing/localchans/log.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package localchans
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btclog/v2"
|
||||
"github.com/lightningnetwork/lnd/build"
|
||||
)
|
||||
|
||||
// log is a logger that is initialized with no output filters. This means the
|
||||
// package will not perform any logging by default until the caller requests
|
||||
// it.
|
||||
var log btclog.Logger
|
||||
|
||||
const Subsystem = "LCHN"
|
||||
|
||||
// The default amount of logging is none.
|
||||
func init() {
|
||||
UseLogger(build.NewSubLogger(Subsystem, nil))
|
||||
}
|
||||
|
||||
// DisableLog disables all library log output. Logging output is disabled by
|
||||
// default until UseLogger is called.
|
||||
func DisableLog() {
|
||||
UseLogger(btclog.Disabled)
|
||||
}
|
||||
|
||||
// UseLogger uses a specified Logger to output package logging info. This
|
||||
// should be used in preference to SetLogWriter if the caller is also using
|
||||
// btclog.
|
||||
func UseLogger(logger btclog.Logger) {
|
||||
log = logger
|
||||
}
|
@@ -1,10 +1,13 @@
|
||||
package localchans
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
@@ -19,6 +22,12 @@ import (
|
||||
// Manager manages the node's local channels. The only operation that is
|
||||
// currently implemented is updating forwarding policies.
|
||||
type Manager struct {
|
||||
// SelfPub contains the public key of the local node.
|
||||
SelfPub *btcec.PublicKey
|
||||
|
||||
// DefaultRoutingPolicy is the default routing policy.
|
||||
DefaultRoutingPolicy models.ForwardingPolicy
|
||||
|
||||
// UpdateForwardingPolicies is used by the manager to update active
|
||||
// links with a new policy.
|
||||
UpdateForwardingPolicies func(
|
||||
@@ -30,7 +39,7 @@ type Manager struct {
|
||||
edgesToUpdate []discovery.EdgeWithInfo) error
|
||||
|
||||
// ForAllOutgoingChannels is required to iterate over all our local
|
||||
// channels.
|
||||
// channels. The ChannelEdgePolicy parameter may be nil.
|
||||
ForAllOutgoingChannels func(cb func(kvdb.RTx,
|
||||
*models.ChannelEdgeInfo,
|
||||
*models.ChannelEdgePolicy) error) error
|
||||
@@ -40,6 +49,9 @@ type Manager struct {
|
||||
FetchChannel func(tx kvdb.RTx, chanPoint wire.OutPoint) (
|
||||
*channeldb.OpenChannel, error)
|
||||
|
||||
// AddEdge is used to add edge/channel to the topology of the router.
|
||||
AddEdge func(edge *models.ChannelEdgeInfo) error
|
||||
|
||||
// policyUpdateLock ensures that the database and the link do not fall
|
||||
// out of sync if there are concurrent fee update calls. Without it,
|
||||
// there is a chance that policy A updates the database, then policy B
|
||||
@@ -51,7 +63,8 @@ type Manager struct {
|
||||
// UpdatePolicy updates the policy for the specified channels on disk and in
|
||||
// the active links.
|
||||
func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
chanPoints ...wire.OutPoint) ([]*lnrpc.FailedUpdate, error) {
|
||||
createMissingEdge bool, chanPoints ...wire.OutPoint) (
|
||||
[]*lnrpc.FailedUpdate, error) {
|
||||
|
||||
r.policyUpdateLock.Lock()
|
||||
defer r.policyUpdateLock.Unlock()
|
||||
@@ -69,10 +82,8 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
var edgesToUpdate []discovery.EdgeWithInfo
|
||||
policiesToUpdate := make(map[wire.OutPoint]models.ForwardingPolicy)
|
||||
|
||||
// Next, we'll loop over all the outgoing channels the router knows of.
|
||||
// If we have a filter then we'll only collected those channels,
|
||||
// otherwise we'll collect them all.
|
||||
err := r.ForAllOutgoingChannels(func(
|
||||
// NOTE: edge may be nil when this function is called.
|
||||
processChan := func(
|
||||
tx kvdb.RTx,
|
||||
info *models.ChannelEdgeInfo,
|
||||
edge *models.ChannelEdgePolicy) error {
|
||||
@@ -88,8 +99,24 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
// will be used to report invalid channels later on.
|
||||
delete(unprocessedChans, info.ChannelPoint)
|
||||
|
||||
if edge == nil {
|
||||
log.Errorf("Got nil channel edge policy when updating "+
|
||||
"a channel. Channel point: %v",
|
||||
info.ChannelPoint.String())
|
||||
|
||||
failedUpdates = append(failedUpdates, makeFailureItem(
|
||||
info.ChannelPoint,
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_NOT_FOUND,
|
||||
"edge policy not found",
|
||||
))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply the new policy to the edge.
|
||||
err := r.updateEdge(tx, info.ChannelPoint, edge, newSchema)
|
||||
err := r.updateEdge(
|
||||
tx, info.ChannelPoint, edge, newSchema,
|
||||
)
|
||||
if err != nil {
|
||||
failedUpdates = append(failedUpdates,
|
||||
makeFailureItem(info.ChannelPoint,
|
||||
@@ -125,7 +152,12 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Next, we'll loop over all the outgoing channels the router knows of.
|
||||
// If we have a filter then we'll only collect those channels, otherwise
|
||||
// we'll collect them all.
|
||||
err := r.ForAllOutgoingChannels(processChan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -155,7 +187,37 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
"not yet confirmed",
|
||||
))
|
||||
|
||||
// If the edge was not found, but the channel is found, that
|
||||
// means the edge is missing in the graph database and should be
|
||||
// recreated. The edge and policy are created in-memory. The
|
||||
// edge is inserted in createEdge below and the policy will be
|
||||
// added to the graph in the PropagateChanPolicyUpdate call
|
||||
// below.
|
||||
case createMissingEdge:
|
||||
log.Warnf("Missing edge for active channel (%s) "+
|
||||
"during policy update. Recreating edge with "+
|
||||
"default policy.",
|
||||
channel.FundingOutpoint.String())
|
||||
|
||||
info, edge, failedUpdate := r.createMissingEdge(
|
||||
channel, newSchema,
|
||||
)
|
||||
if failedUpdate == nil {
|
||||
err = processChan(nil, info, edge)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
failedUpdates = append(
|
||||
failedUpdates, failedUpdate,
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Warnf("Missing edge for active channel (%s) "+
|
||||
"during policy update. Could not update "+
|
||||
"policy.", channel.FundingOutpoint.String())
|
||||
|
||||
failedUpdates = append(failedUpdates,
|
||||
makeFailureItem(chanPoint,
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_UNKNOWN,
|
||||
@@ -180,11 +242,124 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy,
|
||||
return failedUpdates, nil
|
||||
}
|
||||
|
||||
func (r *Manager) createMissingEdge(channel *channeldb.OpenChannel,
|
||||
newSchema routing.ChannelPolicy) (*models.ChannelEdgeInfo,
|
||||
*models.ChannelEdgePolicy, *lnrpc.FailedUpdate) {
|
||||
|
||||
info, edge, err := r.createEdge(channel, time.Now())
|
||||
if err != nil {
|
||||
log.Errorf("Failed to recreate missing edge "+
|
||||
"for channel (%s): %v",
|
||||
channel.FundingOutpoint.String(), err)
|
||||
|
||||
return nil, nil, makeFailureItem(
|
||||
channel.FundingOutpoint,
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_UNKNOWN,
|
||||
"could not update policies",
|
||||
)
|
||||
}
|
||||
|
||||
// Validate the newly created edge policy with the user defined new
|
||||
// schema before adding the edge to the database.
|
||||
err = r.updateEdge(nil, channel.FundingOutpoint, edge, newSchema)
|
||||
if err != nil {
|
||||
return nil, nil, makeFailureItem(
|
||||
info.ChannelPoint,
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_INVALID_PARAMETER,
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// Insert the edge into the database to avoid `edge not
|
||||
// found` errors during policy update propagation.
|
||||
err = r.AddEdge(info)
|
||||
if err != nil {
|
||||
log.Errorf("Attempt to add missing edge for "+
|
||||
"channel (%s) errored with: %v",
|
||||
channel.FundingOutpoint.String(), err)
|
||||
|
||||
return nil, nil, makeFailureItem(
|
||||
channel.FundingOutpoint,
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_UNKNOWN,
|
||||
"could not add edge",
|
||||
)
|
||||
}
|
||||
|
||||
return info, edge, nil
|
||||
}
|
||||
|
||||
// createEdge recreates an edge and policy from an open channel in-memory.
|
||||
func (r *Manager) createEdge(channel *channeldb.OpenChannel,
|
||||
timestamp time.Time) (*models.ChannelEdgeInfo,
|
||||
*models.ChannelEdgePolicy, error) {
|
||||
|
||||
nodeKey1Bytes := r.SelfPub.SerializeCompressed()
|
||||
nodeKey2Bytes := channel.IdentityPub.SerializeCompressed()
|
||||
bitcoinKey1Bytes := channel.LocalChanCfg.MultiSigKey.PubKey.
|
||||
SerializeCompressed()
|
||||
bitcoinKey2Bytes := channel.RemoteChanCfg.MultiSigKey.PubKey.
|
||||
SerializeCompressed()
|
||||
channelFlags := lnwire.ChanUpdateChanFlags(0)
|
||||
|
||||
// Make it such that node_id_1 is the lexicographically-lesser of the
|
||||
// two compressed keys sorted in ascending lexicographic order.
|
||||
if bytes.Compare(nodeKey2Bytes, nodeKey1Bytes) < 0 {
|
||||
nodeKey1Bytes, nodeKey2Bytes = nodeKey2Bytes, nodeKey1Bytes
|
||||
bitcoinKey1Bytes, bitcoinKey2Bytes = bitcoinKey2Bytes,
|
||||
bitcoinKey1Bytes
|
||||
channelFlags = 1
|
||||
}
|
||||
|
||||
var featureBuf bytes.Buffer
|
||||
err := lnwire.NewRawFeatureVector().Encode(&featureBuf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to encode features: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
info := &models.ChannelEdgeInfo{
|
||||
ChannelID: channel.ShortChanID().ToUint64(),
|
||||
ChainHash: channel.ChainHash,
|
||||
Features: featureBuf.Bytes(),
|
||||
Capacity: channel.Capacity,
|
||||
ChannelPoint: channel.FundingOutpoint,
|
||||
}
|
||||
|
||||
copy(info.NodeKey1Bytes[:], nodeKey1Bytes)
|
||||
copy(info.NodeKey2Bytes[:], nodeKey2Bytes)
|
||||
copy(info.BitcoinKey1Bytes[:], bitcoinKey1Bytes)
|
||||
copy(info.BitcoinKey2Bytes[:], bitcoinKey2Bytes)
|
||||
|
||||
// Construct a dummy channel edge policy with default values that will
|
||||
// be updated with the new values in the call to processChan below.
|
||||
timeLockDelta := uint16(r.DefaultRoutingPolicy.TimeLockDelta)
|
||||
edge := &models.ChannelEdgePolicy{
|
||||
ChannelID: channel.ShortChanID().ToUint64(),
|
||||
LastUpdate: timestamp,
|
||||
TimeLockDelta: timeLockDelta,
|
||||
ChannelFlags: channelFlags,
|
||||
MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc,
|
||||
FeeBaseMSat: r.DefaultRoutingPolicy.BaseFee,
|
||||
FeeProportionalMillionths: r.DefaultRoutingPolicy.FeeRate,
|
||||
MinHTLC: r.DefaultRoutingPolicy.MinHTLCOut,
|
||||
MaxHTLC: r.DefaultRoutingPolicy.MaxHTLC,
|
||||
}
|
||||
|
||||
copy(edge.ToNode[:], channel.IdentityPub.SerializeCompressed())
|
||||
|
||||
return info, edge, nil
|
||||
}
|
||||
|
||||
// updateEdge updates the given edge with the new schema.
|
||||
func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint,
|
||||
edge *models.ChannelEdgePolicy,
|
||||
newSchema routing.ChannelPolicy) error {
|
||||
|
||||
channel, err := r.FetchChannel(tx, chanPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update forwarding fee scheme and required time lock delta.
|
||||
edge.FeeBaseMSat = newSchema.BaseFee
|
||||
edge.FeeProportionalMillionths = lnwire.MilliSatoshi(
|
||||
@@ -192,7 +367,7 @@ func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint,
|
||||
)
|
||||
|
||||
// If inbound fees are set, we update the edge with them.
|
||||
err := fn.MapOptionZ(newSchema.InboundFee,
|
||||
err = fn.MapOptionZ(newSchema.InboundFee,
|
||||
func(f models.InboundFee) error {
|
||||
inboundWireFee := f.ToWire()
|
||||
return edge.ExtraOpaqueData.PackRecords(
|
||||
@@ -206,7 +381,7 @@ func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint,
|
||||
edge.TimeLockDelta = uint16(newSchema.TimeLockDelta)
|
||||
|
||||
// Retrieve negotiated channel htlc amt limits.
|
||||
amtMin, amtMax, err := r.getHtlcAmtLimits(tx, chanPoint)
|
||||
amtMin, amtMax, err := r.getHtlcAmtLimits(channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -267,14 +442,9 @@ func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint,
|
||||
|
||||
// getHtlcAmtLimits retrieves the negotiated channel min and max htlc amount
|
||||
// constraints.
|
||||
func (r *Manager) getHtlcAmtLimits(tx kvdb.RTx, chanPoint wire.OutPoint) (
|
||||
func (r *Manager) getHtlcAmtLimits(ch *channeldb.OpenChannel) (
|
||||
lnwire.MilliSatoshi, lnwire.MilliSatoshi, error) {
|
||||
|
||||
ch, err := r.FetchChannel(tx, chanPoint)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
// The max htlc policy field must be less than or equal to the channel
|
||||
// capacity AND less than or equal to the max in-flight HTLC value.
|
||||
// Since the latter is always less than or equal to the former, just
|
||||
|
@@ -1,14 +1,19 @@
|
||||
package localchans
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
"github.com/lightningnetwork/lnd/discovery"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@@ -35,6 +40,18 @@ func TestManager(t *testing.T) {
|
||||
channelSet []channel
|
||||
)
|
||||
|
||||
sp := [33]byte{}
|
||||
_, _ = hex.Decode(sp[:], []byte("028d7500dd4c12685d1f568b4c2b5048e85"+
|
||||
"34b873319f3a8daa612b469132ec7f7"))
|
||||
rp := [33]byte{}
|
||||
_, _ = hex.Decode(rp[:], []byte("034f355bdcb7cc0af728ef3cceb9615d906"+
|
||||
"84bb5b2ca5f859ab0f0b704075871aa"))
|
||||
selfpub, _ := btcec.ParsePubKey(sp[:])
|
||||
remotepub, _ := btcec.ParsePubKey(rp[:])
|
||||
localMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
localMultisigKey := localMultisigPrivKey.PubKey()
|
||||
remoteMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
remoteMultisigKey := remoteMultisigPrivKey.PubKey()
|
||||
newPolicy := routing.ChannelPolicy{
|
||||
FeeSchema: routing.FeeSchema{
|
||||
BaseFee: 100,
|
||||
@@ -131,17 +148,42 @@ func TestManager(t *testing.T) {
|
||||
}
|
||||
|
||||
return &channeldb.OpenChannel{
|
||||
FundingOutpoint: chanPointValid,
|
||||
IdentityPub: remotepub,
|
||||
LocalChanCfg: channeldb.ChannelConfig{
|
||||
ChannelStateBounds: bounds,
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: localMultisigKey,
|
||||
},
|
||||
},
|
||||
RemoteChanCfg: channeldb.ChannelConfig{
|
||||
ChannelStateBounds: bounds,
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: remoteMultisigKey,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
addEdge := func(edge *models.ChannelEdgeInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
manager := Manager{
|
||||
UpdateForwardingPolicies: updateForwardingPolicies,
|
||||
PropagateChanPolicyUpdate: propagateChanPolicyUpdate,
|
||||
ForAllOutgoingChannels: forAllOutgoingChannels,
|
||||
FetchChannel: fetchChannel,
|
||||
SelfPub: selfpub,
|
||||
DefaultRoutingPolicy: models.ForwardingPolicy{
|
||||
MinHTLCOut: minHTLC,
|
||||
MaxHTLC: maxPendingAmount,
|
||||
BaseFee: lnwire.MilliSatoshi(1000),
|
||||
FeeRate: lnwire.MilliSatoshi(0),
|
||||
InboundFee: models.InboundFee{},
|
||||
TimeLockDelta: 80,
|
||||
},
|
||||
AddEdge: addEdge,
|
||||
}
|
||||
|
||||
// Policy with no max htlc value.
|
||||
@@ -156,6 +198,7 @@ func TestManager(t *testing.T) {
|
||||
newPolicy routing.ChannelPolicy
|
||||
channelSet []channel
|
||||
specifiedChanPoints []wire.OutPoint
|
||||
createMissingEdge bool
|
||||
expectedNumUpdates int
|
||||
expectedUpdateFailures []lnrpc.UpdateFailure
|
||||
expectErr error
|
||||
@@ -173,6 +216,7 @@ func TestManager(t *testing.T) {
|
||||
},
|
||||
},
|
||||
specifiedChanPoints: []wire.OutPoint{chanPointValid},
|
||||
createMissingEdge: false,
|
||||
expectedNumUpdates: 1,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{},
|
||||
expectErr: nil,
|
||||
@@ -190,6 +234,7 @@ func TestManager(t *testing.T) {
|
||||
},
|
||||
},
|
||||
specifiedChanPoints: []wire.OutPoint{},
|
||||
createMissingEdge: false,
|
||||
expectedNumUpdates: 1,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{},
|
||||
expectErr: nil,
|
||||
@@ -207,6 +252,7 @@ func TestManager(t *testing.T) {
|
||||
},
|
||||
},
|
||||
specifiedChanPoints: []wire.OutPoint{chanPointMissing},
|
||||
createMissingEdge: false,
|
||||
expectedNumUpdates: 0,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_NOT_FOUND,
|
||||
@@ -228,10 +274,39 @@ func TestManager(t *testing.T) {
|
||||
},
|
||||
},
|
||||
specifiedChanPoints: []wire.OutPoint{chanPointValid},
|
||||
createMissingEdge: false,
|
||||
expectedNumUpdates: 1,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
// Here, the edge is missing, causing the edge to be
|
||||
// recreated.
|
||||
name: "missing edge recreated",
|
||||
currentPolicy: models.ChannelEdgePolicy{},
|
||||
newPolicy: newPolicy,
|
||||
channelSet: []channel{},
|
||||
specifiedChanPoints: []wire.OutPoint{chanPointValid},
|
||||
createMissingEdge: true,
|
||||
expectedNumUpdates: 1,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
// Here, the edge is missing, but the edge will not be
|
||||
// recreated, because createMissingEdge is false.
|
||||
name: "missing edge ignored",
|
||||
currentPolicy: models.ChannelEdgePolicy{},
|
||||
newPolicy: newPolicy,
|
||||
channelSet: []channel{},
|
||||
specifiedChanPoints: []wire.OutPoint{chanPointValid},
|
||||
createMissingEdge: false,
|
||||
expectedNumUpdates: 0,
|
||||
expectedUpdateFailures: []lnrpc.UpdateFailure{
|
||||
lnrpc.UpdateFailure_UPDATE_FAILURE_UNKNOWN,
|
||||
},
|
||||
expectErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -242,6 +317,7 @@ func TestManager(t *testing.T) {
|
||||
expectedNumUpdates = test.expectedNumUpdates
|
||||
|
||||
failedUpdates, err := manager.UpdatePolicy(test.newPolicy,
|
||||
test.createMissingEdge,
|
||||
test.specifiedChanPoints...)
|
||||
|
||||
if len(failedUpdates) != len(test.expectedUpdateFailures) {
|
||||
@@ -258,3 +334,179 @@ func TestManager(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Tests creating a new edge in the manager where the local pubkey is the
|
||||
// lexicographically lesser or the two.
|
||||
func TestCreateEdgeLower(t *testing.T) {
|
||||
sp := [33]byte{}
|
||||
_, _ = hex.Decode(sp[:], []byte("028d7500dd4c12685d1f568b4c2b5048e85"+
|
||||
"34b873319f3a8daa612b469132ec7f7"))
|
||||
rp := [33]byte{}
|
||||
_, _ = hex.Decode(rp[:], []byte("034f355bdcb7cc0af728ef3cceb9615d906"+
|
||||
"84bb5b2ca5f859ab0f0b704075871aa"))
|
||||
selfpub, _ := btcec.ParsePubKey(sp[:])
|
||||
remotepub, _ := btcec.ParsePubKey(rp[:])
|
||||
localMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
localMultisigKey := localMultisigPrivKey.PubKey()
|
||||
remoteMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
remoteMultisigKey := remoteMultisigPrivKey.PubKey()
|
||||
timestamp := time.Now()
|
||||
defaultPolicy := models.ForwardingPolicy{
|
||||
MinHTLCOut: 1,
|
||||
MaxHTLC: 2,
|
||||
BaseFee: 3,
|
||||
FeeRate: 4,
|
||||
InboundFee: models.InboundFee{
|
||||
Base: 5,
|
||||
Rate: 6,
|
||||
},
|
||||
TimeLockDelta: 7,
|
||||
}
|
||||
|
||||
channel := &channeldb.OpenChannel{
|
||||
IdentityPub: remotepub,
|
||||
LocalChanCfg: channeldb.ChannelConfig{
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: localMultisigKey,
|
||||
},
|
||||
},
|
||||
RemoteChanCfg: channeldb.ChannelConfig{
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: remoteMultisigKey,
|
||||
},
|
||||
},
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(8),
|
||||
ChainHash: *chaincfg.RegressionNetParams.GenesisHash,
|
||||
Capacity: 9,
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash([32]byte{}),
|
||||
Index: 0,
|
||||
},
|
||||
}
|
||||
expectedInfo := &models.ChannelEdgeInfo{
|
||||
ChannelID: 8,
|
||||
ChainHash: channel.ChainHash,
|
||||
Features: []byte{0, 0},
|
||||
Capacity: 9,
|
||||
ChannelPoint: channel.FundingOutpoint,
|
||||
NodeKey1Bytes: sp,
|
||||
NodeKey2Bytes: rp,
|
||||
BitcoinKey1Bytes: [33]byte(
|
||||
localMultisigKey.SerializeCompressed()),
|
||||
BitcoinKey2Bytes: [33]byte(
|
||||
remoteMultisigKey.SerializeCompressed()),
|
||||
AuthProof: nil,
|
||||
ExtraOpaqueData: nil,
|
||||
}
|
||||
expectedEdge := &models.ChannelEdgePolicy{
|
||||
ChannelID: 8,
|
||||
LastUpdate: timestamp,
|
||||
TimeLockDelta: 7,
|
||||
ChannelFlags: 0,
|
||||
MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc,
|
||||
FeeBaseMSat: 3,
|
||||
FeeProportionalMillionths: 4,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: 2,
|
||||
SigBytes: nil,
|
||||
ToNode: rp,
|
||||
ExtraOpaqueData: nil,
|
||||
}
|
||||
manager := Manager{
|
||||
SelfPub: selfpub,
|
||||
DefaultRoutingPolicy: defaultPolicy,
|
||||
}
|
||||
|
||||
info, edge, err := manager.createEdge(channel, timestamp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedInfo, info)
|
||||
require.Equal(t, expectedEdge, edge)
|
||||
}
|
||||
|
||||
// Tests creating a new edge in the manager where the local pubkey is the
|
||||
// lexicographically higher or the two.
|
||||
func TestCreateEdgeHigher(t *testing.T) {
|
||||
sp := [33]byte{}
|
||||
_, _ = hex.Decode(sp[:], []byte("034f355bdcb7cc0af728ef3cceb9615d906"+
|
||||
"84bb5b2ca5f859ab0f0b704075871aa"))
|
||||
rp := [33]byte{}
|
||||
_, _ = hex.Decode(rp[:], []byte("028d7500dd4c12685d1f568b4c2b5048e85"+
|
||||
"34b873319f3a8daa612b469132ec7f7"))
|
||||
selfpub, _ := btcec.ParsePubKey(sp[:])
|
||||
remotepub, _ := btcec.ParsePubKey(rp[:])
|
||||
localMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
localMultisigKey := localMultisigPrivKey.PubKey()
|
||||
remoteMultisigPrivKey, _ := btcec.NewPrivateKey()
|
||||
remoteMultisigKey := remoteMultisigPrivKey.PubKey()
|
||||
timestamp := time.Now()
|
||||
defaultPolicy := models.ForwardingPolicy{
|
||||
MinHTLCOut: 1,
|
||||
MaxHTLC: 2,
|
||||
BaseFee: 3,
|
||||
FeeRate: 4,
|
||||
InboundFee: models.InboundFee{
|
||||
Base: 5,
|
||||
Rate: 6,
|
||||
},
|
||||
TimeLockDelta: 7,
|
||||
}
|
||||
|
||||
channel := &channeldb.OpenChannel{
|
||||
IdentityPub: remotepub,
|
||||
LocalChanCfg: channeldb.ChannelConfig{
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: localMultisigKey,
|
||||
},
|
||||
},
|
||||
RemoteChanCfg: channeldb.ChannelConfig{
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
PubKey: remoteMultisigKey,
|
||||
},
|
||||
},
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(8),
|
||||
ChainHash: *chaincfg.RegressionNetParams.GenesisHash,
|
||||
Capacity: 9,
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash([32]byte{}),
|
||||
Index: 0,
|
||||
},
|
||||
}
|
||||
expectedInfo := &models.ChannelEdgeInfo{
|
||||
ChannelID: 8,
|
||||
ChainHash: channel.ChainHash,
|
||||
Features: []byte{0, 0},
|
||||
Capacity: 9,
|
||||
ChannelPoint: channel.FundingOutpoint,
|
||||
NodeKey1Bytes: rp,
|
||||
NodeKey2Bytes: sp,
|
||||
BitcoinKey1Bytes: [33]byte(
|
||||
remoteMultisigKey.SerializeCompressed()),
|
||||
BitcoinKey2Bytes: [33]byte(
|
||||
localMultisigKey.SerializeCompressed()),
|
||||
AuthProof: nil,
|
||||
ExtraOpaqueData: nil,
|
||||
}
|
||||
expectedEdge := &models.ChannelEdgePolicy{
|
||||
ChannelID: 8,
|
||||
LastUpdate: timestamp,
|
||||
TimeLockDelta: 7,
|
||||
ChannelFlags: 1,
|
||||
MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc,
|
||||
FeeBaseMSat: 3,
|
||||
FeeProportionalMillionths: 4,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: 2,
|
||||
SigBytes: nil,
|
||||
ToNode: rp,
|
||||
ExtraOpaqueData: nil,
|
||||
}
|
||||
manager := Manager{
|
||||
SelfPub: selfpub,
|
||||
DefaultRoutingPolicy: defaultPolicy,
|
||||
}
|
||||
|
||||
info, edge, err := manager.createEdge(channel, timestamp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedInfo, info)
|
||||
require.Equal(t, expectedEdge, edge)
|
||||
}
|
||||
|
Reference in New Issue
Block a user