2017-05-01 19:58:08 +03:00
|
|
|
package htlcswitch
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/go-errors/errors"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
)
|
|
|
|
|
|
|
|
// circuitKey uniquely identifies an active circuit between two open channels.
|
|
|
|
// Currently, the payment hash is used to uniquely identify each circuit.
|
|
|
|
type circuitKey [sha256.Size]byte
|
|
|
|
|
2017-06-17 00:38:42 +03:00
|
|
|
// String returns the string representation of the circuitKey.
|
2017-05-01 19:58:08 +03:00
|
|
|
func (k *circuitKey) String() string {
|
|
|
|
return hex.EncodeToString(k[:])
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
// paymentCircuit is used by the htlc switch subsystem to determine the
|
|
|
|
// fowrards/backwards path for the settle/fail HTLC messages. A payment circuit
|
|
|
|
// will be created once a channel link forwards the htlc add request and
|
|
|
|
// removed when we receive settle/fail htlc message.
|
2017-05-01 19:58:08 +03:00
|
|
|
type paymentCircuit struct {
|
|
|
|
// PaymentHash used as unique identifier of payment.
|
|
|
|
PaymentHash circuitKey
|
|
|
|
|
|
|
|
// Src identifies the channel from which add htlc request is came from
|
2017-06-17 00:49:38 +03:00
|
|
|
// and to which settle/fail htlc request will be returned back. Once
|
|
|
|
// the switch forwards the settle/fail message to the src the circuit
|
|
|
|
// is considered to be completed.
|
|
|
|
Src lnwire.ShortChannelID
|
2017-05-01 19:58:08 +03:00
|
|
|
|
|
|
|
// Dest identifies the channel to which we propagate the htlc add
|
|
|
|
// update and from which we are expecting to receive htlc settle/fail
|
|
|
|
// request back.
|
2017-06-17 00:49:38 +03:00
|
|
|
Dest lnwire.ShortChannelID
|
2017-05-01 19:58:08 +03:00
|
|
|
|
|
|
|
// RefCount is used to count the circuits with the same circuit key.
|
|
|
|
RefCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
// newPaymentCircuit creates new payment circuit instance.
|
2017-06-17 00:49:38 +03:00
|
|
|
func newPaymentCircuit(src, dest lnwire.ShortChannelID, key circuitKey) *paymentCircuit {
|
2017-05-01 19:58:08 +03:00
|
|
|
return &paymentCircuit{
|
|
|
|
Src: src,
|
|
|
|
Dest: dest,
|
|
|
|
PaymentHash: key,
|
|
|
|
RefCount: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// isEqual checks the equality of two payment circuits.
|
|
|
|
func (a *paymentCircuit) isEqual(b *paymentCircuit) bool {
|
|
|
|
return bytes.Equal(a.PaymentHash[:], b.PaymentHash[:]) &&
|
|
|
|
a.Src == b.Src &&
|
|
|
|
a.Dest == b.Dest
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
// circuitMap is a data structure that implements thread safe storage of
|
|
|
|
// circuits. Each circuit key (payment hash) may have several of circuits
|
|
|
|
// corresponding to it due to the possibility of repeated payment hashes.
|
2017-05-01 19:58:08 +03:00
|
|
|
//
|
|
|
|
// TODO(andrew.shvv) make it persistent
|
|
|
|
type circuitMap struct {
|
2017-06-17 00:49:38 +03:00
|
|
|
sync.RWMutex
|
2017-05-01 19:58:08 +03:00
|
|
|
circuits map[circuitKey]*paymentCircuit
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
// newCircuitMap creates a new instance of the circuitMap.
|
2017-05-01 19:58:08 +03:00
|
|
|
func newCircuitMap() *circuitMap {
|
|
|
|
return &circuitMap{
|
|
|
|
circuits: make(map[circuitKey]*paymentCircuit),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
// add adds a new active payment circuit to the circuitMap.
|
2017-05-01 19:58:08 +03:00
|
|
|
func (m *circuitMap) add(circuit *paymentCircuit) error {
|
2017-06-17 00:49:38 +03:00
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
// Examine the circuit map to see if this circuit is already in use or
|
|
|
|
// not. If so, then we'll simply increment the reference count.
|
|
|
|
// Otherwise, we'll create a new circuit from scratch.
|
|
|
|
//
|
2017-05-01 19:58:08 +03:00
|
|
|
// TODO(roasbeef): include dest+src+amt in key
|
|
|
|
if c, ok := m.circuits[circuit.PaymentHash]; ok {
|
|
|
|
c.RefCount++
|
2017-06-17 00:49:38 +03:00
|
|
|
return nil
|
2017-05-01 19:58:08 +03:00
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
m.circuits[circuit.PaymentHash] = circuit
|
|
|
|
|
2017-05-01 19:58:08 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:49:38 +03:00
|
|
|
// remove destroys the target circuit by removing it from the circuit map.
|
|
|
|
func (m *circuitMap) remove(key circuitKey) (*paymentCircuit, error) {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
2017-05-01 19:58:08 +03:00
|
|
|
|
|
|
|
if circuit, ok := m.circuits[key]; ok {
|
|
|
|
if circuit.RefCount--; circuit.RefCount == 0 {
|
|
|
|
delete(m.circuits, key)
|
|
|
|
}
|
2017-06-17 01:03:30 +03:00
|
|
|
|
2017-05-01 19:58:08 +03:00
|
|
|
return circuit, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, errors.Errorf("can't find circuit"+
|
|
|
|
" for key %v", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// pending returns number of circuits which are waiting for to be completed
|
2017-06-17 00:49:38 +03:00
|
|
|
// (settle/fail responses to be received).
|
2017-05-01 19:58:08 +03:00
|
|
|
func (m *circuitMap) pending() int {
|
2017-06-17 00:49:38 +03:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2017-05-01 19:58:08 +03:00
|
|
|
|
|
|
|
var length int
|
|
|
|
for _, circuits := range m.circuits {
|
|
|
|
length += circuits.RefCount
|
|
|
|
}
|
|
|
|
|
|
|
|
return length
|
|
|
|
}
|