routing: add channel update validation test
This commit is contained in:
parent
47d2e1e024
commit
ac8a3af84c
@ -14,6 +14,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@ -347,6 +348,171 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestChannelUpdateValidation tests that a failed payment with an associated
|
||||
// channel update will only be applied to the graph when the update contains a
|
||||
// valid signature.
|
||||
func TestChannelUpdateValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Setup a three node network.
|
||||
testChannels := []*testChannel{
|
||||
symmetricTestChannel("a", "b", 100000, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
}, 1),
|
||||
symmetricTestChannel("b", "c", 100000, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
defer testGraph.cleanUp()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
|
||||
const startingBlockHeight = 101
|
||||
|
||||
ctx, cleanUp, err := createTestCtxFromGraphInstance(startingBlockHeight,
|
||||
testGraph)
|
||||
|
||||
defer cleanUp()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create router: %v", err)
|
||||
}
|
||||
|
||||
// Assert that the initially configured fee is retrieved correctly.
|
||||
_, policy, _, err := ctx.router.GetChannelByID(
|
||||
lnwire.NewShortChanIDFromInt(1))
|
||||
if err != nil {
|
||||
t.Fatalf("cannot retrieve channel")
|
||||
}
|
||||
|
||||
if policy.FeeProportionalMillionths != 400 {
|
||||
t.Fatalf("invalid fee")
|
||||
}
|
||||
|
||||
// Setup a route from source a to destination c. The route will be used
|
||||
// in a call to SendToRoute. SendToRoute also applies channel updates,
|
||||
// but it saves us from including RequestRoute in the test scope too.
|
||||
var hop1 [33]byte
|
||||
copy(hop1[:], ctx.aliases["b"].SerializeCompressed())
|
||||
|
||||
var hop2 [33]byte
|
||||
copy(hop2[:], ctx.aliases["c"].SerializeCompressed())
|
||||
|
||||
hops := []*Hop{
|
||||
{
|
||||
Channel: &ChannelHop{
|
||||
ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{
|
||||
ChannelID: 1,
|
||||
Node: &channeldb.LightningNode{
|
||||
PubKeyBytes: hop1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Channel: &ChannelHop{
|
||||
ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{
|
||||
ChannelID: 2,
|
||||
Node: &channeldb.LightningNode{
|
||||
PubKeyBytes: hop2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
route := &Route{
|
||||
Hops: hops,
|
||||
}
|
||||
|
||||
// Set up a channel update message with an invalid signature to be
|
||||
// returned to the sender.
|
||||
var invalidSignature [64]byte
|
||||
errChanUpdate := lnwire.ChannelUpdate{
|
||||
Signature: invalidSignature,
|
||||
FeeRate: 500,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(1),
|
||||
Timestamp: uint32(testTime.Add(time.Minute).Unix()),
|
||||
}
|
||||
|
||||
// We'll modify the SendToSwitch method so that it simulates a failed
|
||||
// payment with an error originating from the first hop of the route.
|
||||
// The unsigned channel update is attached to the failure message.
|
||||
ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID,
|
||||
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: ctx.aliases["b"],
|
||||
FailureMessage: &lnwire.FailFeeInsufficient{
|
||||
Update: errChanUpdate,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// The payment parameter is mostly redundant in SendToRoute. Can be left
|
||||
// empty for this test.
|
||||
payment := &LightningPayment{}
|
||||
|
||||
// Send off the payment request to the router. The specified route
|
||||
// should be attempted and the channel update should be received by
|
||||
// router and ignored because it is missing a valid signature.
|
||||
_, _, err = ctx.router.SendToRoute([]*Route{route}, payment)
|
||||
if err == nil {
|
||||
t.Fatalf("expected route to fail with channel update")
|
||||
}
|
||||
|
||||
_, policy, _, err = ctx.router.GetChannelByID(
|
||||
lnwire.NewShortChanIDFromInt(1))
|
||||
if err != nil {
|
||||
t.Fatalf("cannot retrieve channel")
|
||||
}
|
||||
|
||||
if policy.FeeProportionalMillionths != 400 {
|
||||
t.Fatalf("fee updated without valid signature")
|
||||
}
|
||||
|
||||
// Next, add a signature to the channel update.
|
||||
chanUpdateMsg, err := errChanUpdate.DataToSign()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
digest := chainhash.DoubleHashB(chanUpdateMsg)
|
||||
sig, err := testGraph.privKeyMap["b"].Sign(digest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
errChanUpdate.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Retry the payment using the same route as before.
|
||||
_, _, err = ctx.router.SendToRoute([]*Route{route}, payment)
|
||||
if err == nil {
|
||||
t.Fatalf("expected route to fail with channel update")
|
||||
}
|
||||
|
||||
// This time a valid signature was supplied and the policy change should
|
||||
// have been applied to the graph.
|
||||
_, policy, _, err = ctx.router.GetChannelByID(
|
||||
lnwire.NewShortChanIDFromInt(1))
|
||||
if err != nil {
|
||||
t.Fatalf("cannot retrieve channel")
|
||||
}
|
||||
|
||||
if policy.FeeProportionalMillionths != 500 {
|
||||
t.Fatalf("fee not updated even though signature is valid")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSendPaymentErrorRepeatedFeeInsufficient tests that if we receive
|
||||
// multiple fee related errors from a channel that we're attempting to route
|
||||
// through, then we'll prune the channel after the second attempt.
|
||||
|
Loading…
Reference in New Issue
Block a user