htlcswitch: Change circuit map keys to (channel ID, HTLC ID).

This changes the circuit map internals and API to reference circuits
by a primary key of (channel ID, HTLC ID) instead of paymnet
hash. This is because each circuit has a unique offered HTLC, but
there may be multiple circuits for a payment hash with different
source or destination channels.
This commit is contained in:
Jim Posen authored and Olaoluwa Osuntokun committed 2017-12-14 17:53:58 -08:00
1 parent bc8d674958
commit 1328e61c00
6 files changed
+274 -151

No files matched your search

+49 -62
View File
@@ -129,7 +129,7 @@ type Switch struct {
// circuits is storage for payment circuits which are used to
// forward the settle/fail htlc updates back to the add htlc initiator.
circuits *circuitMap
circuits *CircuitMap
// links is a map of channel id and channel link which manages
// this channel.
@@ -167,7 +167,7 @@ type Switch struct {
func New(cfg Config) *Switch {
return &Switch{
cfg: &cfg,
circuits: newCircuitMap(),
circuits: NewCircuitMap(),
linkIndex: make(map[lnwire.ChannelID]ChannelLink),
forwardingIndex: make(map[lnwire.ShortChannelID]ChannelLink),
interfaceIndex: make(map[[33]byte]map[ChannelLink]struct{}),
@@ -481,7 +481,8 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
}
source.HandleSwitchPacket(&htlcPacket{
src: packet.src,
dest: packet.src,
destID: packet.srcID,
payHash: htlc.PaymentHash,
isObfuscated: true,
htlc: &lnwire.UpdateFailHTLC{
@@ -529,7 +530,8 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
}
source.HandleSwitchPacket(&htlcPacket{
src: packet.src,
dest: packet.src,
destID: packet.srcID,
payHash: htlc.PaymentHash,
isObfuscated: true,
htlc: &lnwire.UpdateFailHTLC{
@@ -544,38 +546,6 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
return err
}
// If packet was forwarded from another channel link than we
// should create circuit (remember the path) in order to
// forward settle/fail packet back.
if err := s.circuits.add(newPaymentCircuit(
source.ShortChanID(),
destination.ShortChanID(),
htlc.PaymentHash,
packet.obfuscator,
)); err != nil {
failure := lnwire.NewTemporaryChannelFailure(nil)
reason, err := packet.obfuscator.EncryptFirstHop(failure)
if err != nil {
err := errors.Errorf("unable to obfuscate "+
"error: %v", err)
log.Error(err)
return err
}
source.HandleSwitchPacket(&htlcPacket{
src: packet.src,
payHash: htlc.PaymentHash,
isObfuscated: true,
htlc: &lnwire.UpdateFailHTLC{
Reason: reason,
},
})
err = errors.Errorf("unable to add circuit: "+
"%v", err)
log.Error(err)
return err
}
// Send the packet to the destination channel link which
// manages the channel.
destination.HandleSwitchPacket(packet)
@@ -585,37 +555,49 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
// payment circuit by forwarding the settle msg to the channel from
// which htlc add packet was initially received.
case *lnwire.UpdateFufillHTLC, *lnwire.UpdateFailHTLC:
// Exit if we can't find and remove the active circuit to
// continue propagating the fail over.
circuit, err := s.circuits.remove(packet.payHash)
if packet.dest == (lnwire.ShortChannelID{}) {
// Use circuit map to find the link to forward settle/fail to.
circuit := s.circuits.LookupByHTLC(packet.src, packet.srcID)
if circuit == nil {
err := errors.Errorf("Unable to find source channel for HTLC "+
"settle/fail: channel ID = %s, HTLC ID = %d, "+
"payment hash = %x", packet.src, packet.srcID,
packet.payHash[:])
log.Error(err)
return err
}
// Remove circuit since we are about to complete the HTLC.
err := s.circuits.Remove(packet.src, packet.srcID)
if err != nil {
log.Warnf("Failed to close completed onion circuit for %x: "+
"%s<->%s", packet.payHash[:], circuit.IncomingChanID,
circuit.OutgoingChanID)
} else {
log.Debugf("Closed completed onion circuit for %x: %s<->%s",
packet.payHash[:], circuit.IncomingChanID,
circuit.OutgoingChanID)
}
// Obfuscate the error message for fail updates before sending back
// through the circuit.
if htlc, ok := htlc.(*lnwire.UpdateFailHTLC); ok && !packet.isObfuscated {
htlc.Reason = circuit.ErrorEncrypter.IntermediateEncrypt(
htlc.Reason)
}
packet.dest = circuit.IncomingChanID
packet.destID = circuit.IncomingHTLCID
}
source, err := s.getLinkByShortID(packet.dest)
if err != nil {
err := errors.Errorf("unable to remove "+
"circuit for payment hash: %v", packet.payHash)
err := errors.Errorf("Unable to get source channel link to "+
"forward HTLC settle/fail: %v", err)
log.Error(err)
return err
}
// If this is failure than we need to obfuscate the error.
if htlc, ok := htlc.(*lnwire.UpdateFailHTLC); ok && !packet.isObfuscated {
htlc.Reason = circuit.ErrorEncrypter.IntermediateEncrypt(
htlc.Reason,
)
}
// Propagating settle/fail htlc back to src of add htlc packet.
source, err := s.getLinkByShortID(circuit.Src)
if err != nil {
err := errors.Errorf("unable to get source "+
"channel link to forward settle/fail htlc: %v",
err)
log.Error(err)
return err
}
log.Debugf("Closing completed onion "+
"circuit for %x: %v<->%v", packet.payHash[:],
circuit.Src, circuit.Dest)
source.HandleSwitchPacket(packet)
return nil
@@ -1109,3 +1091,8 @@ func (s *Switch) numPendingPayments() int {
return l
}
// addCircuit adds a circuit to the switch's in-memory mapping.
func (s *Switch) addCircuit(circuit *PaymentCircuit) {
s.circuits.Add(circuit)
}