routing+lnd: provide payment premiere as response to SendPayment
This commit is contained in:
parent
ef6ddcf788
commit
2dfab8c6d7
@ -26,6 +26,10 @@ const (
|
|||||||
htlcQueueSize = 50
|
htlcQueueSize = 50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
zeroBytes [32]byte
|
||||||
|
)
|
||||||
|
|
||||||
// link represents an active channel capable of forwarding HTLCs. Each
|
// link represents an active channel capable of forwarding HTLCs. Each
|
||||||
// active channel registered with the htlc switch creates a new link which will
|
// active channel registered with the htlc switch creates a new link which will
|
||||||
// be used for forwarding outgoing HTLCs. The link also has additional
|
// be used for forwarding outgoing HTLCs. The link also has additional
|
||||||
@ -60,6 +64,8 @@ type htlcPacket struct {
|
|||||||
payHash [32]byte
|
payHash [32]byte
|
||||||
amt btcutil.Amount
|
amt btcutil.Amount
|
||||||
|
|
||||||
|
preImage chan [32]byte
|
||||||
|
|
||||||
err chan error
|
err chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,9 +131,9 @@ type htlcSwitch struct {
|
|||||||
interfaceMtx sync.RWMutex
|
interfaceMtx sync.RWMutex
|
||||||
interfaces map[chainhash.Hash][]*link
|
interfaces map[chainhash.Hash][]*link
|
||||||
|
|
||||||
// onionIndex is an index used to properly forward a message
|
// onionIndex is an index used to properly forward a message to the
|
||||||
// to the next hop within a Sphinx circuit. Within the sphinx packets,
|
// next hop within a Sphinx circuit. Within the sphinx packets, the
|
||||||
// the "next-hop" destination is encoded as the hash160 of the node's
|
// "next-hop" destination is encoded as the hash160 of the node's
|
||||||
// public key serialized in compressed format.
|
// public key serialized in compressed format.
|
||||||
onionMtx sync.RWMutex
|
onionMtx sync.RWMutex
|
||||||
onionIndex map[[ripemd160.Size]byte][]*link
|
onionIndex map[[ripemd160.Size]byte][]*link
|
||||||
@ -145,11 +151,11 @@ type htlcSwitch struct {
|
|||||||
// the RPC system.
|
// the RPC system.
|
||||||
outgoingPayments chan *htlcPacket
|
outgoingPayments chan *htlcPacket
|
||||||
|
|
||||||
// htlcPlex is the channel which all connected links use to
|
// htlcPlex is the channel which all connected links use to coordinate
|
||||||
// coordinate the setup/teardown of Sphinx (onion routing) payment
|
// the setup/teardown of Sphinx (onion routing) payment circuits.
|
||||||
// circuits. Active links forward any add/settle messages over this
|
// Active links forward any add/settle messages over this channel each
|
||||||
// channel each state transition, sending new adds/settles which are
|
// state transition, sending new adds/settles which are fully locked
|
||||||
// fully locked in.
|
// in.
|
||||||
htlcPlex chan *htlcPacket
|
htlcPlex chan *htlcPacket
|
||||||
|
|
||||||
// TODO(roasbeef): sampler to log sat/sec and tx/sec
|
// TODO(roasbeef): sampler to log sat/sec and tx/sec
|
||||||
@ -206,12 +212,13 @@ func (h *htlcSwitch) Stop() error {
|
|||||||
// In the event that the interface has insufficient capacity for the payment,
|
// In the event that the interface has insufficient capacity for the payment,
|
||||||
// an error is returned. Additionally, if the interface cannot be found, an
|
// an error is returned. Additionally, if the interface cannot be found, an
|
||||||
// alternative error is returned.
|
// alternative error is returned.
|
||||||
func (h *htlcSwitch) SendHTLC(htlcPkt *htlcPacket) error {
|
func (h *htlcSwitch) SendHTLC(htlcPkt *htlcPacket) ([32]byte, error) {
|
||||||
htlcPkt.err = make(chan error, 1)
|
htlcPkt.err = make(chan error, 1)
|
||||||
|
htlcPkt.preImage = make(chan [32]byte, 1)
|
||||||
|
|
||||||
h.outgoingPayments <- htlcPkt
|
h.outgoingPayments <- htlcPkt
|
||||||
|
|
||||||
return <-htlcPkt.err
|
return <-htlcPkt.preImage, <-htlcPkt.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// htlcForwarder is responsible for optimally forwarding (and possibly
|
// htlcForwarder is responsible for optimally forwarding (and possibly
|
||||||
@ -243,6 +250,7 @@ out:
|
|||||||
err := fmt.Errorf("Unable to locate link %x",
|
err := fmt.Errorf("Unable to locate link %x",
|
||||||
dest[:])
|
dest[:])
|
||||||
hswcLog.Errorf(err.Error())
|
hswcLog.Errorf(err.Error())
|
||||||
|
htlcPkt.preImage <- zeroBytes
|
||||||
htlcPkt.err <- err
|
htlcPkt.err <- err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -277,6 +285,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
hswcLog.Errorf("Unable to send payment, insufficient capacity")
|
hswcLog.Errorf("Unable to send payment, insufficient capacity")
|
||||||
|
htlcPkt.preImage <- zeroBytes
|
||||||
htlcPkt.err <- fmt.Errorf("Insufficient capacity")
|
htlcPkt.err <- fmt.Errorf("Insufficient capacity")
|
||||||
case pkt := <-h.htlcPlex:
|
case pkt := <-h.htlcPlex:
|
||||||
// TODO(roasbeef): properly account with cleared vs settled
|
// TODO(roasbeef): properly account with cleared vs settled
|
||||||
@ -373,8 +382,9 @@ out:
|
|||||||
// continue propagating the HTLC across the
|
// continue propagating the HTLC across the
|
||||||
// network.
|
// network.
|
||||||
circuit.clear.linkChan <- &htlcPacket{
|
circuit.clear.linkChan <- &htlcPacket{
|
||||||
msg: wireMsg,
|
msg: wireMsg,
|
||||||
err: make(chan error, 1),
|
preImage: make(chan [32]byte, 1),
|
||||||
|
err: make(chan error, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the available bandwidth for the link
|
// Reduce the available bandwidth for the link
|
||||||
|
16
peer.go
16
peer.go
@ -1055,7 +1055,8 @@ type pendingPayment struct {
|
|||||||
htlc *lnwire.UpdateAddHTLC
|
htlc *lnwire.UpdateAddHTLC
|
||||||
index uint64
|
index uint64
|
||||||
|
|
||||||
err chan error
|
preImage chan [32]byte
|
||||||
|
err chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
// commitmentState is the volatile+persistent state of an active channel's
|
// commitmentState is the volatile+persistent state of an active channel's
|
||||||
@ -1314,9 +1315,10 @@ func (p *peer) handleDownStreamPkt(state *commitmentState, pkt *htlcPacket) {
|
|||||||
p.queueMsg(htlc, nil)
|
p.queueMsg(htlc, nil)
|
||||||
|
|
||||||
state.pendingBatch = append(state.pendingBatch, &pendingPayment{
|
state.pendingBatch = append(state.pendingBatch, &pendingPayment{
|
||||||
htlc: htlc,
|
htlc: htlc,
|
||||||
index: index,
|
index: index,
|
||||||
err: pkt.err,
|
preImage: pkt.preImage,
|
||||||
|
err: pkt.err,
|
||||||
})
|
})
|
||||||
|
|
||||||
case *lnwire.UpdateFufillHTLC:
|
case *lnwire.UpdateFufillHTLC:
|
||||||
@ -1565,15 +1567,17 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) {
|
|||||||
if p, ok := state.clearedHTCLs[parentIndex]; ok {
|
if p, ok := state.clearedHTCLs[parentIndex]; ok {
|
||||||
switch htlc.EntryType {
|
switch htlc.EntryType {
|
||||||
// If the HTLC was settled successfully, then
|
// If the HTLC was settled successfully, then
|
||||||
// we return a nil error back to the possible
|
// we return a nil error as well as the payment
|
||||||
// caller.
|
// preimage back to the possible caller.
|
||||||
case lnwallet.Settle:
|
case lnwallet.Settle:
|
||||||
|
p.preImage <- htlc.RPreimage
|
||||||
p.err <- nil
|
p.err <- nil
|
||||||
|
|
||||||
// Otherwise, the HTLC failed, so we propagate
|
// Otherwise, the HTLC failed, so we propagate
|
||||||
// the error back to the potential caller.
|
// the error back to the potential caller.
|
||||||
case lnwallet.Fail:
|
case lnwallet.Fail:
|
||||||
errMsg := state.cancelReasons[parentIndex]
|
errMsg := state.cancelReasons[parentIndex]
|
||||||
|
p.preImage <- [32]byte{}
|
||||||
p.err <- errors.New(errMsg.String())
|
p.err <- errors.New(errMsg.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ type Config struct {
|
|||||||
// denoted by its public key. A non-nil error is to be returned if the
|
// denoted by its public key. A non-nil error is to be returned if the
|
||||||
// payment was unsuccessful.
|
// payment was unsuccessful.
|
||||||
SendToSwitch func(firstHop *btcec.PublicKey,
|
SendToSwitch func(firstHop *btcec.PublicKey,
|
||||||
htlcAdd *lnwire.UpdateAddHTLC) error
|
htlcAdd *lnwire.UpdateAddHTLC) ([32]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChannelRouter is the layer 3 router within the Lightning stack. Below the
|
// ChannelRouter is the layer 3 router within the Lightning stack. Below the
|
||||||
@ -1105,14 +1105,20 @@ type LightningPayment struct {
|
|||||||
// payment is successful, or all candidates routes have been attempted and
|
// payment is successful, or all candidates routes have been attempted and
|
||||||
// resulted in a failed payment. If the payment succeeds, then a non-nil Route
|
// resulted in a failed payment. If the payment succeeds, then a non-nil Route
|
||||||
// will be returned which describes the path the successful payment traversed
|
// will be returned which describes the path the successful payment traversed
|
||||||
// within the network to reach the destination.
|
// within the network to reach the destination. Additionally, the payment
|
||||||
func (r *ChannelRouter) SendPayment(payment *LightningPayment) (*Route, error) {
|
// preimage will also be returned.
|
||||||
|
func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
preImage [32]byte
|
||||||
|
)
|
||||||
|
|
||||||
// Query the graph for a potential path to the destination node that
|
// Query the graph for a potential path to the destination node that
|
||||||
// can support our payment amount. If a path is ultimately unavailable,
|
// can support our payment amount. If a path is ultimately unavailable,
|
||||||
// then an error will be returned.
|
// then an error will be returned.
|
||||||
route, err := r.FindRoute(payment.Target, payment.Amount)
|
route, err := r.FindRoute(payment.Target, payment.Amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return preImage, nil, err
|
||||||
}
|
}
|
||||||
log.Tracef("Selected route for payment: %#v", route)
|
log.Tracef("Selected route for payment: %#v", route)
|
||||||
|
|
||||||
@ -1120,7 +1126,7 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) (*Route, error) {
|
|||||||
// htlcAdd message that we send directly to the switch.
|
// htlcAdd message that we send directly to the switch.
|
||||||
sphinxPacket, err := generateSphinxPacket(route, payment.PaymentHash[:])
|
sphinxPacket, err := generateSphinxPacket(route, payment.PaymentHash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return preImage, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Craft an HTLC packet to send to the layer 2 switch. The metadata
|
// Craft an HTLC packet to send to the layer 2 switch. The metadata
|
||||||
@ -1135,11 +1141,12 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) (*Route, error) {
|
|||||||
// Attempt to send this payment through the network to complete the
|
// Attempt to send this payment through the network to complete the
|
||||||
// payment. If this attempt fails, then we'll bail our early.
|
// payment. If this attempt fails, then we'll bail our early.
|
||||||
firstHop := route.Hops[0].Channel.Node.PubKey
|
firstHop := route.Hops[0].Channel.Node.PubKey
|
||||||
if err := r.cfg.SendToSwitch(firstHop, htlcAdd); err != nil {
|
preImage, err = r.cfg.SendToSwitch(firstHop, htlcAdd)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return preImage, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return route, nil
|
return preImage, route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TopologyClient...
|
// TopologyClient...
|
||||||
|
11
rpcserver.go
11
rpcserver.go
@ -965,7 +965,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
Amount: amt,
|
Amount: amt,
|
||||||
PaymentHash: rHash,
|
PaymentHash: rHash,
|
||||||
}
|
}
|
||||||
route, err := r.server.chanRouter.SendPayment(payment)
|
preImage, route, err := r.server.chanRouter.SendPayment(payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
return
|
return
|
||||||
@ -978,9 +978,9 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): tack on payment hash also?
|
|
||||||
err = paymentStream.Send(&lnrpc.SendResponse{
|
err = paymentStream.Send(&lnrpc.SendResponse{
|
||||||
PaymentRoute: marshalRoute(route),
|
PaymentPreimage: preImage[:],
|
||||||
|
PaymentRoute: marshalRoute(route),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
@ -1047,7 +1047,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
// Finally, send a payment request to the channel router. If the
|
// Finally, send a payment request to the channel router. If the
|
||||||
// payment succeeds, then the returned route will be that was used
|
// payment succeeds, then the returned route will be that was used
|
||||||
// successfully within the payment.
|
// successfully within the payment.
|
||||||
route, err := r.server.chanRouter.SendPayment(&routing.LightningPayment{
|
preImage, route, err := r.server.chanRouter.SendPayment(&routing.LightningPayment{
|
||||||
Target: destPub,
|
Target: destPub,
|
||||||
Amount: amt,
|
Amount: amt,
|
||||||
PaymentHash: rHash,
|
PaymentHash: rHash,
|
||||||
@ -1063,7 +1063,8 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &lnrpc.SendResponse{
|
return &lnrpc.SendResponse{
|
||||||
PaymentRoute: marshalRoute(route),
|
PaymentPreimage: preImage[:],
|
||||||
|
PaymentRoute: marshalRoute(route),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ func newServer(listenAddrs []string, notifier chainntnfs.ChainNotifier,
|
|||||||
Broadcast: s.broadcastMessage,
|
Broadcast: s.broadcastMessage,
|
||||||
SendMessages: s.sendToPeer,
|
SendMessages: s.sendToPeer,
|
||||||
SendToSwitch: func(firstHop *btcec.PublicKey,
|
SendToSwitch: func(firstHop *btcec.PublicKey,
|
||||||
htlcAdd *lnwire.UpdateAddHTLC) error {
|
htlcAdd *lnwire.UpdateAddHTLC) ([32]byte, error) {
|
||||||
|
|
||||||
firstHopPub := firstHop.SerializeCompressed()
|
firstHopPub := firstHop.SerializeCompressed()
|
||||||
destInterface := chainhash.Hash(fastsha256.Sum256(firstHopPub))
|
destInterface := chainhash.Hash(fastsha256.Sum256(firstHopPub))
|
||||||
|
Loading…
Reference in New Issue
Block a user