package htlcswitch import ( "errors" "fmt" "github.com/lightningnetwork/lnd/channeldb/models" ) // heldHtlcSet keeps track of outstanding intercepted forwards. It exposes // several methods to manipulate the underlying map structure in a consistent // way. type heldHtlcSet struct { set map[models.CircuitKey]InterceptedForward } func newHeldHtlcSet() *heldHtlcSet { return &heldHtlcSet{ set: make(map[models.CircuitKey]InterceptedForward), } } // forEach iterates over all held forwards and calls the given callback for each // of them. func (h *heldHtlcSet) forEach(cb func(InterceptedForward)) { for _, fwd := range h.set { cb(fwd) } } // popAll calls the callback for each forward and removes them from the set. func (h *heldHtlcSet) popAll(cb func(InterceptedForward)) { for _, fwd := range h.set { cb(fwd) } h.set = make(map[models.CircuitKey]InterceptedForward) } // popAutoFails calls the callback for each forward that has an auto-fail height // equal or less then the specified pop height and removes them from the set. func (h *heldHtlcSet) popAutoFails(height uint32, cb func(InterceptedForward)) { for key, fwd := range h.set { if uint32(fwd.Packet().AutoFailHeight) > height { continue } cb(fwd) delete(h.set, key) } } // pop returns the specified forward and removes it from the set. func (h *heldHtlcSet) pop(key models.CircuitKey) (InterceptedForward, error) { intercepted, ok := h.set[key] if !ok { return nil, fmt.Errorf("fwd %v not found", key) } delete(h.set, key) return intercepted, nil } // exists tests whether the specified forward is part of the set. func (h *heldHtlcSet) exists(key models.CircuitKey) bool { _, ok := h.set[key] return ok } // push adds the specified forward to the set. An error is returned if the // forward exists already. func (h *heldHtlcSet) push(key models.CircuitKey, fwd InterceptedForward) error { if fwd == nil { return errors.New("nil fwd pushed") } if h.exists(key) { return errors.New("htlc already exists in set") } h.set[key] = fwd return nil }