rpcserver: modify SendPayment to use new routing pkg API
This commit is contained in:
parent
abfef02df2
commit
ea6f6d6069
135
rpcserver.go
135
rpcserver.go
@ -609,7 +609,8 @@ func (r *rpcServer) ListChannels(ctx context.Context,
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func constructPayment(path []graph.Vertex, amount btcutil.Amount, rHash []byte) *channeldb.OutgoingPayment {
|
func constructPayment(route *routing.Route, amount btcutil.Amount,
|
||||||
|
rHash []byte) *channeldb.OutgoingPayment {
|
||||||
|
|
||||||
payment := &channeldb.OutgoingPayment{}
|
payment := &channeldb.OutgoingPayment{}
|
||||||
|
|
||||||
@ -621,9 +622,10 @@ func constructPayment(path []graph.Vertex, amount btcutil.Amount, rHash []byte)
|
|||||||
payment.Invoice.CreationDate = time.Now()
|
payment.Invoice.CreationDate = time.Now()
|
||||||
payment.Timestamp = time.Now()
|
payment.Timestamp = time.Now()
|
||||||
|
|
||||||
pathBytes33 := make([][33]byte, len(path))
|
pathBytes33 := make([][33]byte, len(route.Hops))
|
||||||
for i:=0; i<len(path); i++ {
|
for i, hop := range route.Hops {
|
||||||
pathBytes33[i] = path[i].ToByte33()
|
hopPub := hop.Channel.Node.PubKey.SerializeCompressed()
|
||||||
|
copy(pathBytes33[i][:], hopPub)
|
||||||
}
|
}
|
||||||
payment.Path = pathBytes33
|
payment.Path = pathBytes33
|
||||||
return payment
|
return payment
|
||||||
@ -670,9 +672,15 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return err
|
return err
|
||||||
case nextPayment := <-payChan:
|
case nextPayment := <-payChan:
|
||||||
// Query the routing table for a potential path to the
|
// Parse the details of the payment which include the
|
||||||
// destination node. If a path is ultimately
|
// pubkey of the destination and the payment amount.
|
||||||
// unavailable, then an error will be returned.
|
dest := nextPayment.Dest
|
||||||
|
amt := btcutil.Amount(nextPayment.Amt)
|
||||||
|
destNode, err := btcec.ParsePubKey(dest, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
// If we're in debug HTLC mode, then all outgoing
|
// If we're in debug HTLC mode, then all outgoing
|
||||||
// HTLC's will pay to the same debug rHash. Otherwise,
|
// HTLC's will pay to the same debug rHash. Otherwise,
|
||||||
// we pay to the rHash specified within the RPC
|
// we pay to the rHash specified within the RPC
|
||||||
@ -683,18 +691,19 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
} else {
|
} else {
|
||||||
copy(rHash[:], nextPayment.PaymentHash)
|
copy(rHash[:], nextPayment.PaymentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct and HTLC packet which a payment route (if
|
// Construct and HTLC packet which a payment route (if
|
||||||
// one is found) to the destination using a Sphinx
|
// one is found) to the destination using a Sphinx
|
||||||
// onoin packet to encode the route.
|
// onion packet to encode the route.
|
||||||
htlcPkt, path, err := r.constructPaymentRoute([]byte(nextPayment.Dest),
|
htlcPkt, route, err := r.constructPaymentRoute(destNode, amt,
|
||||||
nextPayment.Amt, rHash)
|
rHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rpcsLog.Tracef("[sendpayment] selected route: %v", path)
|
|
||||||
// We launch a new goroutine to execute the current
|
// We launch a new goroutine to execute the current
|
||||||
// payment so we can continue to serve requests while
|
// payment so we can continue to serve requests while
|
||||||
// this payment is being dispatiched.
|
// this payment is being dispatched.
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): semaphore to limit num outstanding
|
// TODO(roasbeef): semaphore to limit num outstanding
|
||||||
// goroutines.
|
// goroutines.
|
||||||
@ -707,10 +716,13 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save payment to DB.
|
// Save the completed payment to the database
|
||||||
payment := constructPayment(path,
|
// for record keeping purposes.
|
||||||
btcutil.Amount(nextPayment.Amt), rHash[:])
|
payment := constructPayment(route, amt, rHash[:])
|
||||||
r.server.chanDB.AddPayment(payment)
|
if err := r.server.chanDB.AddPayment(payment); err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): proper responses
|
// TODO(roasbeef): proper responses
|
||||||
resp := &lnrpc.SendResponse{}
|
resp := &lnrpc.SendResponse{}
|
||||||
@ -747,11 +759,21 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
copy(rHash[:], paymentHash)
|
copy(rHash[:], paymentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pubBytes, err := hex.DecodeString(nextPayment.DestString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
destPub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
amt := btcutil.Amount(nextPayment.Amt)
|
||||||
|
|
||||||
// Construct and HTLC packet which a payment route (if
|
// Construct and HTLC packet which a payment route (if
|
||||||
// one is found) to the destination using a Sphinx
|
// one is found) to the destination using a Sphinx
|
||||||
// onoin packet to encode the route.
|
// onoin packet to encode the route.
|
||||||
htlcPkt, path, err := r.constructPaymentRoute([]byte(nextPayment.DestString),
|
htlcPkt, route, err := r.constructPaymentRoute(destPub, amt, rHash)
|
||||||
nextPayment.Amt, rHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -761,8 +783,12 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
if err := r.server.htlcSwitch.SendHTLC(htlcPkt); err != nil {
|
if err := r.server.htlcSwitch.SendHTLC(htlcPkt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payment := constructPayment(path, btcutil.Amount(nextPayment.Amt), rHash[:])
|
|
||||||
r.server.chanDB.AddPayment(payment)
|
payment := constructPayment(route, amt, rHash[:])
|
||||||
|
if err := r.server.chanDB.AddPayment(payment); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &lnrpc.SendResponse{}, nil
|
return &lnrpc.SendResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,25 +796,24 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
// encapsulates a Sphinx onion packet that encodes the end-to-end route any
|
// encapsulates a Sphinx onion packet that encodes the end-to-end route any
|
||||||
// payment instructions necessary to complete an HTLC. If a route is unable to
|
// payment instructions necessary to complete an HTLC. If a route is unable to
|
||||||
// be located, then an error is returned indicating as much.
|
// be located, then an error is returned indicating as much.
|
||||||
func (r *rpcServer) constructPaymentRoute(destPubkey []byte, amt int64,
|
func (r *rpcServer) constructPaymentRoute(destNode *btcec.PublicKey,
|
||||||
rHash [32]byte) (*htlcPacket, []graph.Vertex, error) {
|
amt btcutil.Amount, rHash [32]byte) (*htlcPacket, *routing.Route, error) {
|
||||||
|
|
||||||
const queryTimeout = time.Duration(time.Second * 10)
|
const queryTimeout = time.Duration(time.Second * 10)
|
||||||
|
|
||||||
// Query the routing table for a potential path to the destination
|
// Query the channel router for a potential path to the destination
|
||||||
// node. If a path is ultimately unavailable, then an error will be
|
// node that can support our payment amount. If a path is ultimately
|
||||||
// returned.
|
// unavailable, then an error will be returned.
|
||||||
targetVertex := graph.NewVertex(destPubkey)
|
route, err := r.server.chanRouter.FindRoute(destNode, amt)
|
||||||
path, err := r.server.routingMgr.FindPath(targetVertex)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
rpcsLog.Tracef("[sendpayment] selected route: %v", path)
|
rpcsLog.Tracef("[sendpayment] selected route: %#v", route)
|
||||||
|
|
||||||
// Generate the raw encoded sphinx packet to be included along with the
|
// Generate the raw encoded sphinx packet to be included along with the
|
||||||
// HTLC add message. We snip off the first hop from the path as within
|
// HTLC add message. We snip off the first hop from the path as within
|
||||||
// the routing table's star graph, we're always the first hop.
|
// the routing table's star graph, we're always the first hop.
|
||||||
sphinxPacket, err := generateSphinxPacket(path[1:], rHash[:])
|
sphinxPacket, err := generateSphinxPacket(route, rHash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -797,39 +822,38 @@ func (r *rpcServer) constructPaymentRoute(destPubkey []byte, amt int64,
|
|||||||
// meta-data within this packet will be used to route the payment
|
// meta-data within this packet will be used to route the payment
|
||||||
// through the network.
|
// through the network.
|
||||||
htlcAdd := &lnwire.HTLCAddRequest{
|
htlcAdd := &lnwire.HTLCAddRequest{
|
||||||
Amount: btcutil.Amount(amt),
|
Amount: route.TotalAmount,
|
||||||
RedemptionHashes: [][32]byte{rHash},
|
RedemptionHashes: [][32]byte{rHash},
|
||||||
OnionBlob: sphinxPacket,
|
OnionBlob: sphinxPacket,
|
||||||
}
|
}
|
||||||
|
|
||||||
firstHopPub := path[1].ToByte()
|
firstHopPub := route.Hops[0].Channel.Node.PubKey.SerializeCompressed()
|
||||||
destInterface := wire.ShaHash(fastsha256.Sum256(firstHopPub))
|
destInterface := wire.ShaHash(fastsha256.Sum256(firstHopPub))
|
||||||
|
|
||||||
return &htlcPacket{
|
return &htlcPacket{
|
||||||
dest: destInterface,
|
dest: destInterface,
|
||||||
msg: htlcAdd,
|
msg: htlcAdd,
|
||||||
}, path, nil
|
}, route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateSphinxPacket generates then encodes a sphinx packet which encodes
|
// generateSphinxPacket generates then encodes a sphinx packet which encodes
|
||||||
// the onion route specified by the passed list of graph vertexes. The blob
|
// the onion route specified by the passed layer 3 route. The blob returned
|
||||||
// returned from this function can immediately be included within an HTLC add
|
// from this function can immediately be included within an HTLC add packet to
|
||||||
// packet to be sent to the first hop within the route.
|
// be sent to the first hop within the route.
|
||||||
func generateSphinxPacket(vertexes []graph.Vertex, paymentHash []byte) ([]byte, error) {
|
func generateSphinxPacket(route *routing.Route, paymentHash []byte) ([]byte, error) {
|
||||||
// First convert all the vertexs from the routing table to in-memory
|
// First obtain all the public keys along the route which are contained
|
||||||
// public key objects. These objects are necessary in order to perform
|
// in each hop.
|
||||||
// the series of ECDH operations required to construct the Sphinx
|
nodes := make([]*btcec.PublicKey, len(route.Hops))
|
||||||
// packet below.
|
for i, hop := range route.Hops {
|
||||||
route := make([]*btcec.PublicKey, len(vertexes))
|
// We create a new instance of the public key to avoid possibly
|
||||||
for i, vertex := range vertexes {
|
// mutating the curve parameters, which are unset in a higher
|
||||||
vertexBytes := vertex.ToByte()
|
// level in order to avoid spamming the logs.
|
||||||
|
pub := btcec.PublicKey{
|
||||||
pub, err := btcec.ParsePubKey(vertexBytes, btcec.S256())
|
btcec.S256(),
|
||||||
if err != nil {
|
hop.Channel.Node.PubKey.X,
|
||||||
return nil, err
|
hop.Channel.Node.PubKey.Y,
|
||||||
}
|
}
|
||||||
|
nodes[i] = &pub
|
||||||
route[i] = pub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next we generate the per-hop payload which gives each node within
|
// Next we generate the per-hop payload which gives each node within
|
||||||
@ -838,7 +862,7 @@ func generateSphinxPacket(vertexes []graph.Vertex, paymentHash []byte) ([]byte,
|
|||||||
// TODO(roasbeef): properly set CLTV value, payment amount, and chain
|
// TODO(roasbeef): properly set CLTV value, payment amount, and chain
|
||||||
// within hop paylods.
|
// within hop paylods.
|
||||||
var hopPayloads [][]byte
|
var hopPayloads [][]byte
|
||||||
for i := 0; i < len(route); i++ {
|
for i := 0; i < len(route.Hops); i++ {
|
||||||
payload := bytes.Repeat([]byte{byte('A' + i)},
|
payload := bytes.Repeat([]byte{byte('A' + i)},
|
||||||
sphinx.HopPayloadSize)
|
sphinx.HopPayloadSize)
|
||||||
hopPayloads = append(hopPayloads, payload)
|
hopPayloads = append(hopPayloads, payload)
|
||||||
@ -852,13 +876,13 @@ func generateSphinxPacket(vertexes []graph.Vertex, paymentHash []byte) ([]byte,
|
|||||||
// Next generate the onion routing packet which allows
|
// Next generate the onion routing packet which allows
|
||||||
// us to perform privacy preserving source routing
|
// us to perform privacy preserving source routing
|
||||||
// across the network.
|
// across the network.
|
||||||
sphinxPacket, err := sphinx.NewOnionPacket(route, sessionKey,
|
sphinxPacket, err := sphinx.NewOnionPacket(nodes, sessionKey,
|
||||||
hopPayloads, paymentHash)
|
hopPayloads, paymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, encode Sphinx packet using it's wire represenation to be
|
// Finally, encode Sphinx packet using it's wire representation to be
|
||||||
// included within the HTLC add packet.
|
// included within the HTLC add packet.
|
||||||
var onionBlob bytes.Buffer
|
var onionBlob bytes.Buffer
|
||||||
if err := sphinxPacket.Encode(&onionBlob); err != nil {
|
if err := sphinxPacket.Encode(&onionBlob); err != nil {
|
||||||
@ -1154,7 +1178,6 @@ func (r *rpcServer) ShowRoutingTable(ctx context.Context,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ListPayments returns a list of all outgoing payments.
|
// ListPayments returns a list of all outgoing payments.
|
||||||
func (r *rpcServer) ListPayments(context.Context,
|
func (r *rpcServer) ListPayments(context.Context,
|
||||||
*lnrpc.ListPaymentsRequest) (*lnrpc.ListPaymentsResponse, error) {
|
*lnrpc.ListPaymentsRequest) (*lnrpc.ListPaymentsResponse, error) {
|
||||||
@ -1169,13 +1192,13 @@ func (r *rpcServer) ListPayments(context.Context,
|
|||||||
paymentsResp := &lnrpc.ListPaymentsResponse{
|
paymentsResp := &lnrpc.ListPaymentsResponse{
|
||||||
Payments: make([]*lnrpc.Payment, len(payments)),
|
Payments: make([]*lnrpc.Payment, len(payments)),
|
||||||
}
|
}
|
||||||
for i:=0; i<len(payments); i++ {
|
for i := 0; i < len(payments); i++ {
|
||||||
p := &lnrpc.Payment{}
|
p := &lnrpc.Payment{}
|
||||||
p.CreationDate = payments[i].CreationDate.Unix()
|
p.CreationDate = payments[i].CreationDate.Unix()
|
||||||
p.Value = int64(payments[i].Terms.Value)
|
p.Value = int64(payments[i].Terms.Value)
|
||||||
p.RHash = hex.EncodeToString(payments[i].RHash[:])
|
p.RHash = hex.EncodeToString(payments[i].RHash[:])
|
||||||
path := make([]string, len(payments[i].Path))
|
path := make([]string, len(payments[i].Path))
|
||||||
for j:=0; j<len(path); j++ {
|
for j := 0; j < len(path); j++ {
|
||||||
path[j] = hex.EncodeToString(payments[i].Path[j][:])
|
path[j] = hex.EncodeToString(payments[i].Path[j][:])
|
||||||
}
|
}
|
||||||
p.Path = path
|
p.Path = path
|
||||||
@ -1194,4 +1217,4 @@ func (r *rpcServer) DeleteAllPayments(context.Context,
|
|||||||
err := r.server.chanDB.DeleteAllPayments()
|
err := r.server.chanDB.DeleteAllPayments()
|
||||||
resp := &lnrpc.DeleteAllPaymentsResponse{}
|
resp := &lnrpc.DeleteAllPaymentsResponse{}
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user