circuit.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package htlcswitch
  2. import (
  3. "encoding/binary"
  4. "io"
  5. "github.com/lightningnetwork/lnd/channeldb"
  6. "github.com/lightningnetwork/lnd/channeldb/models"
  7. "github.com/lightningnetwork/lnd/htlcswitch/hop"
  8. "github.com/lightningnetwork/lnd/lnwire"
  9. )
  10. // EmptyCircuitKey is a default value for an outgoing circuit key returned when
  11. // a circuit's keystone has not been set. Note that this value is invalid for
  12. // use as a keystone, since the outgoing channel id can never be equal to
  13. // sourceHop.
  14. var EmptyCircuitKey CircuitKey
  15. // CircuitKey is a tuple of channel ID and HTLC ID, used to uniquely identify
  16. // HTLCs in a circuit. Circuits are identified primarily by the circuit key of
  17. // the incoming HTLC. However, a circuit may also be referenced by its outgoing
  18. // circuit key after the HTLC has been forwarded via the outgoing link.
  19. type CircuitKey = models.CircuitKey
  20. // PaymentCircuit is used by the switch as placeholder between when the
  21. // switch makes a forwarding decision and the outgoing link determines the
  22. // proper HTLC ID for the local log. After the outgoing HTLC ID has been
  23. // determined, the half circuit will be converted into a full PaymentCircuit.
  24. type PaymentCircuit struct {
  25. // AddRef is the forward reference of the Add update in the incoming
  26. // link's forwarding package. This value is set on the htlcPacket of the
  27. // returned settle/fail so that it can be removed from disk.
  28. AddRef channeldb.AddRef
  29. // Incoming is the circuit key identifying the incoming channel and htlc
  30. // index from which this ADD originates.
  31. Incoming CircuitKey
  32. // Outgoing is the circuit key identifying the outgoing channel, and the
  33. // HTLC index that was used to forward the ADD. It will be nil if this
  34. // circuit's keystone has not been set.
  35. Outgoing *CircuitKey
  36. // PaymentHash used as unique identifier of payment.
  37. PaymentHash [32]byte
  38. // IncomingAmount is the value of the HTLC from the incoming link.
  39. IncomingAmount lnwire.MilliSatoshi
  40. // OutgoingAmount specifies the value of the HTLC leaving the switch,
  41. // either as a payment or forwarded amount.
  42. OutgoingAmount lnwire.MilliSatoshi
  43. // ErrorEncrypter is used to re-encrypt the onion failure before
  44. // sending it back to the originator of the payment.
  45. ErrorEncrypter hop.ErrorEncrypter
  46. // LoadedFromDisk is set true for any circuits loaded after the circuit
  47. // map is reloaded from disk.
  48. //
  49. // NOTE: This value is determined implicitly during a restart. It is not
  50. // persisted, and should never be set outside the circuit map.
  51. LoadedFromDisk bool
  52. }
  53. // HasKeystone returns true if an outgoing link has assigned this circuit's
  54. // outgoing circuit key.
  55. func (c *PaymentCircuit) HasKeystone() bool {
  56. return c.Outgoing != nil
  57. }
  58. // newPaymentCircuit initializes a payment circuit on the heap using the payment
  59. // hash and an in-memory htlc packet.
  60. func newPaymentCircuit(hash *[32]byte, pkt *htlcPacket) *PaymentCircuit {
  61. var addRef channeldb.AddRef
  62. if pkt.sourceRef != nil {
  63. addRef = *pkt.sourceRef
  64. }
  65. return &PaymentCircuit{
  66. AddRef: addRef,
  67. Incoming: CircuitKey{
  68. ChanID: pkt.incomingChanID,
  69. HtlcID: pkt.incomingHTLCID,
  70. },
  71. PaymentHash: *hash,
  72. IncomingAmount: pkt.incomingAmount,
  73. OutgoingAmount: pkt.amount,
  74. ErrorEncrypter: pkt.obfuscator,
  75. }
  76. }
  77. // makePaymentCircuit initializes a payment circuit on the stack using the
  78. // payment hash and an in-memory htlc packet.
  79. func makePaymentCircuit(hash *[32]byte, pkt *htlcPacket) PaymentCircuit {
  80. var addRef channeldb.AddRef
  81. if pkt.sourceRef != nil {
  82. addRef = *pkt.sourceRef
  83. }
  84. return PaymentCircuit{
  85. AddRef: addRef,
  86. Incoming: CircuitKey{
  87. ChanID: pkt.incomingChanID,
  88. HtlcID: pkt.incomingHTLCID,
  89. },
  90. PaymentHash: *hash,
  91. IncomingAmount: pkt.incomingAmount,
  92. OutgoingAmount: pkt.amount,
  93. ErrorEncrypter: pkt.obfuscator,
  94. }
  95. }
  96. // Encode writes a PaymentCircuit to the provided io.Writer.
  97. func (c *PaymentCircuit) Encode(w io.Writer) error {
  98. if err := c.AddRef.Encode(w); err != nil {
  99. return err
  100. }
  101. if err := c.Incoming.Encode(w); err != nil {
  102. return err
  103. }
  104. if _, err := w.Write(c.PaymentHash[:]); err != nil {
  105. return err
  106. }
  107. var scratch [8]byte
  108. binary.BigEndian.PutUint64(scratch[:], uint64(c.IncomingAmount))
  109. if _, err := w.Write(scratch[:]); err != nil {
  110. return err
  111. }
  112. binary.BigEndian.PutUint64(scratch[:], uint64(c.OutgoingAmount))
  113. if _, err := w.Write(scratch[:]); err != nil {
  114. return err
  115. }
  116. // Defaults to EncrypterTypeNone.
  117. var encrypterType hop.EncrypterType
  118. if c.ErrorEncrypter != nil {
  119. encrypterType = c.ErrorEncrypter.Type()
  120. }
  121. err := binary.Write(w, binary.BigEndian, encrypterType)
  122. if err != nil {
  123. return err
  124. }
  125. // Skip encoding of error encrypter if this half add does not have one.
  126. if encrypterType == hop.EncrypterTypeNone {
  127. return nil
  128. }
  129. return c.ErrorEncrypter.Encode(w)
  130. }
  131. // Decode reads a PaymentCircuit from the provided io.Reader.
  132. func (c *PaymentCircuit) Decode(r io.Reader) error {
  133. if err := c.AddRef.Decode(r); err != nil {
  134. return err
  135. }
  136. if err := c.Incoming.Decode(r); err != nil {
  137. return err
  138. }
  139. if _, err := io.ReadFull(r, c.PaymentHash[:]); err != nil {
  140. return err
  141. }
  142. var scratch [8]byte
  143. if _, err := io.ReadFull(r, scratch[:]); err != nil {
  144. return err
  145. }
  146. c.IncomingAmount = lnwire.MilliSatoshi(
  147. binary.BigEndian.Uint64(scratch[:]))
  148. if _, err := io.ReadFull(r, scratch[:]); err != nil {
  149. return err
  150. }
  151. c.OutgoingAmount = lnwire.MilliSatoshi(
  152. binary.BigEndian.Uint64(scratch[:]))
  153. // Read the encrypter type used for this circuit.
  154. var encrypterType hop.EncrypterType
  155. err := binary.Read(r, binary.BigEndian, &encrypterType)
  156. if err != nil {
  157. return err
  158. }
  159. switch encrypterType {
  160. case hop.EncrypterTypeNone:
  161. // No encrypter was provided, such as when the payment is
  162. // locally initiated.
  163. return nil
  164. case hop.EncrypterTypeSphinx:
  165. // Sphinx encrypter was used as this is a forwarded HTLC.
  166. c.ErrorEncrypter = hop.NewSphinxErrorEncrypter()
  167. case hop.EncrypterTypeMock:
  168. // Test encrypter.
  169. c.ErrorEncrypter = NewMockObfuscator()
  170. case hop.EncrypterTypeIntroduction:
  171. c.ErrorEncrypter = hop.NewIntroductionErrorEncrypter()
  172. case hop.EncrypterTypeRelaying:
  173. c.ErrorEncrypter = hop.NewRelayingErrorEncrypter()
  174. default:
  175. return UnknownEncrypterType(encrypterType)
  176. }
  177. return c.ErrorEncrypter.Decode(r)
  178. }
  179. // InKey returns the primary identifier for the circuit corresponding to the
  180. // incoming HTLC.
  181. func (c *PaymentCircuit) InKey() CircuitKey {
  182. return c.Incoming
  183. }
  184. // OutKey returns the keystone identifying the outgoing link and HTLC ID. If the
  185. // circuit hasn't been completed, this method returns an EmptyKeystone, which is
  186. // an invalid outgoing circuit key. Only call this method if HasKeystone returns
  187. // true.
  188. func (c *PaymentCircuit) OutKey() CircuitKey {
  189. if c.Outgoing != nil {
  190. return *c.Outgoing
  191. }
  192. return EmptyCircuitKey
  193. }