router: convert Route.ToHopPayloads() to Route.ToSphinxPath()
In this commit, we update the process that we use to generate a sphinx packet to send our onion routed HTLC. Due to recent changes in the `sphinx` package we use, we now need to use a new PaymentPath struct. As a result, it no longer makes sense to split up the nodes in a route and their per hop paylods as they're now in the same struct. All tests have been updated accordingly.
This commit is contained in:
parent
cba803b856
commit
bab957382f
@ -807,19 +807,22 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
|
||||
// Next, we'll assert that the "next hop" field in each route payload
|
||||
// properly points to the channel ID that the HTLC should be forwarded
|
||||
// along.
|
||||
hopPayloads := route.ToHopPayloads()
|
||||
if len(hopPayloads) != expectedHopCount {
|
||||
sphinxPath, err := route.ToSphinxPath()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to make sphinx path: %v", err)
|
||||
}
|
||||
if sphinxPath.TrueRouteLength() != expectedHopCount {
|
||||
t.Fatalf("incorrect number of hop payloads: expected %v, got %v",
|
||||
expectedHopCount, len(hopPayloads))
|
||||
expectedHopCount, sphinxPath.TrueRouteLength())
|
||||
}
|
||||
|
||||
// Hops should point to the next hop
|
||||
for i := 0; i < len(expectedHops)-1; i++ {
|
||||
var expectedHop [8]byte
|
||||
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].ChannelID)
|
||||
if !bytes.Equal(hopPayloads[i].NextAddress[:], expectedHop[:]) {
|
||||
if !bytes.Equal(sphinxPath[i].HopData.NextAddress[:], expectedHop[:]) {
|
||||
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
|
||||
expectedHop[:], hopPayloads[i].NextAddress)
|
||||
expectedHop[:], sphinxPath[i].HopData.NextAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,9 +830,9 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
|
||||
// to indicate it's the exit hop.
|
||||
var exitHop [8]byte
|
||||
lastHopIndex := len(expectedHops) - 1
|
||||
if !bytes.Equal(hopPayloads[lastHopIndex].NextAddress[:], exitHop[:]) {
|
||||
if !bytes.Equal(sphinxPath[lastHopIndex].HopData.NextAddress[:], exitHop[:]) {
|
||||
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
|
||||
exitHop[:], hopPayloads[lastHopIndex].NextAddress)
|
||||
exitHop[:], sphinxPath[lastHopIndex].HopData.NextAddress)
|
||||
}
|
||||
|
||||
var expectedTotalFee lnwire.MilliSatoshi
|
||||
|
@ -104,40 +104,6 @@ func (r *Route) HopFee(hopIndex int) lnwire.MilliSatoshi {
|
||||
return incomingAmt - r.Hops[hopIndex].AmtToForward
|
||||
}
|
||||
|
||||
// ToHopPayloads converts a complete route into the series of per-hop payloads
|
||||
// that is to be encoded within each HTLC using an opaque Sphinx packet.
|
||||
func (r *Route) ToHopPayloads() []sphinx.HopData {
|
||||
hopPayloads := make([]sphinx.HopData, len(r.Hops))
|
||||
|
||||
// For each hop encoded within the route, we'll convert the hop struct
|
||||
// to the matching per-hop payload struct as used by the sphinx
|
||||
// package.
|
||||
for i, hop := range r.Hops {
|
||||
hopPayloads[i] = sphinx.HopData{
|
||||
// TODO(roasbeef): properly set realm, make sphinx type
|
||||
// an enum actually?
|
||||
Realm: 0,
|
||||
ForwardAmount: uint64(hop.AmtToForward),
|
||||
OutgoingCltv: hop.OutgoingTimeLock,
|
||||
}
|
||||
|
||||
// As a base case, the next hop is set to all zeroes in order
|
||||
// to indicate that the "last hop" as no further hops after it.
|
||||
nextHop := uint64(0)
|
||||
|
||||
// If we aren't on the last hop, then we set the "next address"
|
||||
// field to be the channel that directly follows it.
|
||||
if i != len(r.Hops)-1 {
|
||||
nextHop = r.Hops[i+1].ChannelID
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint64(hopPayloads[i].NextAddress[:],
|
||||
nextHop)
|
||||
}
|
||||
|
||||
return hopPayloads
|
||||
}
|
||||
|
||||
// NewRouteFromHops creates a new Route structure from the minimally required
|
||||
// information to perform the payment. It infers fee amounts and populates the
|
||||
// node, chan and prev/next hop maps.
|
||||
@ -163,3 +129,49 @@ func NewRouteFromHops(amtToSend lnwire.MilliSatoshi, timeLock uint32,
|
||||
|
||||
return route, nil
|
||||
}
|
||||
|
||||
// ToSphinxPath converts a complete route into a sphinx PaymentPath that
|
||||
// contains the per-hop paylods used to encoding the HTLC routing data for each
|
||||
// hop in the route.
|
||||
func (r *Route) ToSphinxPath() (*sphinx.PaymentPath, error) {
|
||||
var path sphinx.PaymentPath
|
||||
|
||||
// For each hop encoded within the route, we'll convert the hop struct
|
||||
// to an OnionHop with matching per-hop payload within the path as used
|
||||
// by the sphinx package.
|
||||
for i, hop := range r.Hops {
|
||||
pub, err := btcec.ParsePubKey(
|
||||
hop.PubKeyBytes[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path[i] = sphinx.OnionHop{
|
||||
NodePub: *pub,
|
||||
HopData: sphinx.HopData{
|
||||
// TODO(roasbeef): properly set realm, make
|
||||
// sphinx type an enum actually?
|
||||
Realm: [1]byte{0},
|
||||
ForwardAmount: uint64(hop.AmtToForward),
|
||||
OutgoingCltv: hop.OutgoingTimeLock,
|
||||
},
|
||||
}
|
||||
|
||||
// As a base case, the next hop is set to all zeroes in order
|
||||
// to indicate that the "last hop" as no further hops after it.
|
||||
nextHop := uint64(0)
|
||||
|
||||
// If we aren't on the last hop, then we set the "next address"
|
||||
// field to be the channel that directly follows it.
|
||||
if i != len(r.Hops)-1 {
|
||||
nextHop = r.Hops[i+1].ChannelID
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint64(
|
||||
path[i].HopData.NextAddress[:], nextHop,
|
||||
)
|
||||
}
|
||||
|
||||
return &path, nil
|
||||
}
|
||||
|
@ -1467,30 +1467,25 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte) ([]byte,
|
||||
return nil, nil, route.ErrNoRouteHopsProvided
|
||||
}
|
||||
|
||||
// First obtain all the public keys along the route which are contained
|
||||
// in each hop.
|
||||
nodes := make([]*btcec.PublicKey, len(rt.Hops))
|
||||
for i, hop := range rt.Hops {
|
||||
pub, err := btcec.ParsePubKey(hop.PubKeyBytes[:],
|
||||
btcec.S256())
|
||||
// Now that we know we have an actual route, we'll map the route into a
|
||||
// sphinx payument path which includes per-hop paylods for each hop
|
||||
// that give each node within the route the necessary information
|
||||
// (fees, CLTV value, etc) to properly forward the payment.
|
||||
sphinxPath, err := rt.ToSphinxPath()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
nodes[i] = pub
|
||||
}
|
||||
|
||||
// Next we generate the per-hop payload which gives each node within
|
||||
// the route the necessary information (fees, CLTV value, etc) to
|
||||
// properly forward the payment.
|
||||
hopPayloads := rt.ToHopPayloads()
|
||||
|
||||
log.Tracef("Constructed per-hop payloads for payment_hash=%x: %v",
|
||||
paymentHash[:], newLogClosure(func() string {
|
||||
return spew.Sdump(hopPayloads)
|
||||
return spew.Sdump(sphinxPath[:sphinxPath.TrueRouteLength()])
|
||||
}),
|
||||
)
|
||||
|
||||
// Generate a new random session key to ensure that we don't trigger
|
||||
// any replay.
|
||||
//
|
||||
// TODO(roasbeef): add more sources of randomness?
|
||||
sessionKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -1499,7 +1494,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte) ([]byte,
|
||||
// Next generate the onion routing packet which allows us to perform
|
||||
// privacy preserving source routing across the network.
|
||||
sphinxPacket, err := sphinx.NewOnionPacket(
|
||||
nodes, sessionKey, hopPayloads, paymentHash,
|
||||
sphinxPath, sessionKey, paymentHash,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -1523,7 +1518,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte) ([]byte,
|
||||
|
||||
return onionBlob.Bytes(), &sphinx.Circuit{
|
||||
SessionKey: sessionKey,
|
||||
PaymentPath: nodes,
|
||||
PaymentPath: sphinxPath.NodeKeys(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user