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
|
// 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
|
// properly points to the channel ID that the HTLC should be forwarded
|
||||||
// along.
|
// along.
|
||||||
hopPayloads := route.ToHopPayloads()
|
sphinxPath, err := route.ToSphinxPath()
|
||||||
if len(hopPayloads) != expectedHopCount {
|
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",
|
t.Fatalf("incorrect number of hop payloads: expected %v, got %v",
|
||||||
expectedHopCount, len(hopPayloads))
|
expectedHopCount, sphinxPath.TrueRouteLength())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hops should point to the next hop
|
// Hops should point to the next hop
|
||||||
for i := 0; i < len(expectedHops)-1; i++ {
|
for i := 0; i < len(expectedHops)-1; i++ {
|
||||||
var expectedHop [8]byte
|
var expectedHop [8]byte
|
||||||
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].ChannelID)
|
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",
|
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.
|
// to indicate it's the exit hop.
|
||||||
var exitHop [8]byte
|
var exitHop [8]byte
|
||||||
lastHopIndex := len(expectedHops) - 1
|
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",
|
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
|
var expectedTotalFee lnwire.MilliSatoshi
|
||||||
|
@ -104,40 +104,6 @@ func (r *Route) HopFee(hopIndex int) lnwire.MilliSatoshi {
|
|||||||
return incomingAmt - r.Hops[hopIndex].AmtToForward
|
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
|
// NewRouteFromHops creates a new Route structure from the minimally required
|
||||||
// information to perform the payment. It infers fee amounts and populates the
|
// information to perform the payment. It infers fee amounts and populates the
|
||||||
// node, chan and prev/next hop maps.
|
// node, chan and prev/next hop maps.
|
||||||
@ -163,3 +129,49 @@ func NewRouteFromHops(amtToSend lnwire.MilliSatoshi, timeLock uint32,
|
|||||||
|
|
||||||
return route, nil
|
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
|
return nil, nil, route.ErrNoRouteHopsProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
// First obtain all the public keys along the route which are contained
|
// Now that we know we have an actual route, we'll map the route into a
|
||||||
// in each hop.
|
// sphinx payument path which includes per-hop paylods for each hop
|
||||||
nodes := make([]*btcec.PublicKey, len(rt.Hops))
|
// that give each node within the route the necessary information
|
||||||
for i, hop := range rt.Hops {
|
// (fees, CLTV value, etc) to properly forward the payment.
|
||||||
pub, err := btcec.ParsePubKey(hop.PubKeyBytes[:],
|
sphinxPath, err := rt.ToSphinxPath()
|
||||||
btcec.S256())
|
if err != nil {
|
||||||
if err != nil {
|
return nil, nil, err
|
||||||
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",
|
log.Tracef("Constructed per-hop payloads for payment_hash=%x: %v",
|
||||||
paymentHash[:], newLogClosure(func() string {
|
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())
|
sessionKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
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
|
// Next generate the onion routing packet which allows us to perform
|
||||||
// privacy preserving source routing across the network.
|
// privacy preserving source routing across the network.
|
||||||
sphinxPacket, err := sphinx.NewOnionPacket(
|
sphinxPacket, err := sphinx.NewOnionPacket(
|
||||||
nodes, sessionKey, hopPayloads, paymentHash,
|
sphinxPath, sessionKey, paymentHash,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -1523,7 +1518,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte) ([]byte,
|
|||||||
|
|
||||||
return onionBlob.Bytes(), &sphinx.Circuit{
|
return onionBlob.Bytes(), &sphinx.Circuit{
|
||||||
SessionKey: sessionKey,
|
SessionKey: sessionKey,
|
||||||
PaymentPath: nodes,
|
PaymentPath: sphinxPath.NodeKeys(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user