From 7e006371ed92a07413c00b3da36a5faee435c2cd Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 9 Jul 2018 18:12:34 -0700 Subject: [PATCH] router+server: use first hop channel id rather than node key --- routing/router.go | 21 ++++++++++---------- routing/router_test.go | 45 ++++++++++++++++++++++++------------------ server.go | 6 ++++-- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/routing/router.go b/routing/router.go index 4d62de286dce..1aa89eef4994 100644 --- a/routing/router.go +++ b/routing/router.go @@ -2,6 +2,7 @@ package routing import ( "bytes" + "crypto/sha256" "fmt" "runtime" "sort" @@ -9,22 +10,19 @@ import ( "sync/atomic" "time" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" "github.com/coreos/bbolt" "github.com/davecgh/go-spew/spew" + "github.com/go-errors/errors" + "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/multimutex" "github.com/lightningnetwork/lnd/routing/chainview" - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcutil" - - "crypto/sha256" - - "github.com/go-errors/errors" - "github.com/lightningnetwork/lightning-onion" ) const ( @@ -151,7 +149,8 @@ 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 [33]byte, htlcAdd *lnwire.UpdateAddHTLC, + SendToSwitch func(firstHop lnwire.ShortChannelID, + htlcAdd *lnwire.UpdateAddHTLC, circuit *sphinx.Circuit) ([sha256.Size]byte, error) // ChannelPruneExpiry is the duration used to determine if a channel @@ -1711,7 +1710,9 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // 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.PubKeyBytes + firstHop := lnwire.NewShortChanIDFromInt( + route.Hops[0].Channel.ChannelID, + ) preImage, sendError = r.cfg.SendToSwitch( firstHop, htlcAdd, circuit, ) diff --git a/routing/router_test.go b/routing/router_test.go index 1ceb0a90b396..5cf58580d014 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -46,7 +46,7 @@ func (c *testCtx) RestartRouter() error { Graph: c.graph, Chain: c.chain, ChainView: c.chainView, - SendToSwitch: func(_ [33]byte, + SendToSwitch: func(_ lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { return [32]byte{}, nil }, @@ -121,8 +121,8 @@ func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func() Graph: graph, Chain: chain, ChainView: chainView, - SendToSwitch: func(_ [33]byte, _ *lnwire.UpdateAddHTLC, - _ *sphinx.Circuit) ([32]byte, error) { + SendToSwitch: func(_ lnwire.ShortChannelID, + _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { return [32]byte{}, nil }, @@ -295,10 +295,11 @@ 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 [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) { + roasbeefLuoji := lnwire.NewShortChanIDFromInt(689530843) + if firstHop == roasbeefLuoji { pub, err := sourceNode.PubKey() if err != nil { return preImage, err @@ -392,10 +393,11 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to Son goku. This will be a fee related error, so // it should only cause the edge to be pruned after the second attempt. - ctx.router.cfg.SendToSwitch = func(n [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(sourceNode.SerializeCompressed(), n[:]) { + roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID) + if firstHop == roasbeefSongoku { return [32]byte{}, &htlcswitch.ForwardingError{ ErrorSource: sourceNode, @@ -472,6 +474,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { // errors that we'll get back due to disagrements in what the current // block height is. chanID := uint64(3495345) + roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID) _, _, edgeUpateToFail, err := ctx.graph.FetchChannelEdgesByID(chanID) if err != nil { t.Fatalf("unable to fetch chan id: %v", err) @@ -494,10 +497,10 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { // outgoing channel to son goku. Since this is a time lock related // error, we should fail the payment flow all together, as Goku is the // only channel to Sophon. - ctx.router.cfg.SendToSwitch = func(n [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(sourceNode.SerializeCompressed(), n[:]) { + if firstHop == roasbeefSongoku { return [32]byte{}, &htlcswitch.ForwardingError{ ErrorSource: sourceNode, FailureMessage: &lnwire.FailExpiryTooSoon{ @@ -546,10 +549,10 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { // We'll now modify the error return an IncorrectCltvExpiry error // instead, this should result in the same behavior of roasbeef routing // around the faulty Son Goku node. - ctx.router.cfg.SendToSwitch = func(n [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(sourceNode.SerializeCompressed(), n[:]) { + if firstHop == roasbeefSongoku { return [32]byte{}, &htlcswitch.ForwardingError{ ErrorSource: sourceNode, FailureMessage: &lnwire.FailIncorrectCltvExpiry{ @@ -608,16 +611,18 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { t.Fatalf("unable to fetch source node pub: %v", err) } + roasbeefLuoji := lnwire.NewShortChanIDFromInt(689530843) + // 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 [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) { + if firstHop == roasbeefLuoji { // We'll first simulate an error from the first // outgoing link to simulate the channel from luo ji to // roasbeef not having enough capacity. @@ -630,7 +635,8 @@ 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 bytes.Equal(ctx.aliases["satoshi"].SerializeCompressed(), n[:]) { + roasbeefSatoshi := lnwire.NewShortChanIDFromInt(2340213491) + if firstHop == roasbeefSatoshi { return [32]byte{}, &htlcswitch.ForwardingError{ ErrorSource: ctx.aliases["satoshi"], FailureMessage: &lnwire.FailUnknownNextPeer{}, @@ -660,10 +666,10 @@ 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 [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) { + if firstHop == roasbeefLuoji { return [32]byte{}, &htlcswitch.ForwardingError{ ErrorSource: sourcePub, FailureMessage: &lnwire.FailUnknownNextPeer{}, @@ -701,9 +707,10 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { // Finally, we'll modify the SendToSwitch function to indicate that the // roasbeef -> luoji channel has insufficient capacity. This should // again cause us to instead go via the satoshi route. - ctx.router.cfg.SendToSwitch = func(n [33]byte, + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { - if bytes.Equal(ctx.aliases["luoji"].SerializeCompressed(), n[:]) { + + if firstHop == roasbeefLuoji { // We'll first simulate an error from the first // outgoing link to simulate the channel from luo ji to // roasbeef not having enough capacity. @@ -1272,7 +1279,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { Graph: ctx.graph, Chain: ctx.chain, ChainView: ctx.chainView, - SendToSwitch: func(_ [33]byte, + SendToSwitch: func(_ lnwire.ShortChannelID, _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { return [32]byte{}, nil }, diff --git a/server.go b/server.go index d8ed46ca1f8d..194e3df9bae6 100644 --- a/server.go +++ b/server.go @@ -483,7 +483,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, Graph: chanGraph, Chain: cc.chainIO, ChainView: cc.chainView, - SendToSwitch: func(firstHopPub [33]byte, + SendToSwitch: func(firstHop lnwire.ShortChannelID, htlcAdd *lnwire.UpdateAddHTLC, circuit *sphinx.Circuit) ([32]byte, error) { @@ -494,7 +494,9 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, OnionErrorDecrypter: sphinx.NewOnionErrorDecrypter(circuit), } - return s.htlcSwitch.SendHTLC(firstHopPub, htlcAdd, errorDecryptor) + return s.htlcSwitch.SendHTLC( + firstHop, htlcAdd, errorDecryptor, + ) }, ChannelPruneExpiry: time.Duration(time.Hour * 24 * 14), GraphPruneInterval: time.Duration(time.Hour),