-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lsps2: framework for scid management
There's a background watcher that scans the lightning node for in-use scids. These scids are cached in memory. There's a table containing the scids in use for the LSP. `ScidService.ReserveNewScid` attempts to reserve an unused scid. It tries a few times, just in case it runs into a collision. To tie this PR together into something working: - Initialize a `lightning.ScidCache` - Run `LightningClient.WatchScids` on either the CLN or LND client - Initialize a `jit.ScidCleaner` and start it - Initialize a `jit.ScidService` - Call `ScidService.ReserveNewScid` to reserve a scid
- Loading branch information
Showing
10 changed files
with
420 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package lightning | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/breez/lspd/basetypes" | ||
) | ||
|
||
type ScidCacheReader interface { | ||
ContainsScid(scid basetypes.ShortChannelID) bool | ||
} | ||
|
||
type ScidCacheWriter interface { | ||
AddScids(scids ...basetypes.ShortChannelID) | ||
RemoveScids(scids ...basetypes.ShortChannelID) | ||
ReplaceScids(scids []basetypes.ShortChannelID) | ||
} | ||
|
||
type ScidCache struct { | ||
activeScids map[uint64]bool | ||
mtx sync.RWMutex | ||
} | ||
|
||
func NewScidCache() *ScidCache { | ||
return &ScidCache{ | ||
activeScids: make(map[uint64]bool), | ||
} | ||
} | ||
|
||
func (s *ScidCache) ContainsScid( | ||
scid basetypes.ShortChannelID, | ||
) bool { | ||
s.mtx.RLock() | ||
defer s.mtx.RUnlock() | ||
|
||
_, ok := s.activeScids[uint64(scid)] | ||
return ok | ||
} | ||
|
||
func (s *ScidCache) AddScids( | ||
scids ...basetypes.ShortChannelID, | ||
) { | ||
s.mtx.Lock() | ||
defer s.mtx.Unlock() | ||
|
||
for _, scid := range scids { | ||
s.activeScids[uint64(scid)] = true | ||
} | ||
} | ||
|
||
func (s *ScidCache) RemoveScids( | ||
scids ...basetypes.ShortChannelID, | ||
) { | ||
s.mtx.Lock() | ||
defer s.mtx.Unlock() | ||
|
||
for _, scid := range scids { | ||
delete(s.activeScids, uint64(scid)) | ||
} | ||
} | ||
|
||
func (s *ScidCache) ReplaceScids( | ||
scids []basetypes.ShortChannelID, | ||
) { | ||
s.mtx.Lock() | ||
defer s.mtx.Unlock() | ||
|
||
s.activeScids = make(map[uint64]bool) | ||
for _, scid := range scids { | ||
s.activeScids[uint64(scid)] = true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package lsps2 | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"time" | ||
) | ||
|
||
type ScidCleaner struct { | ||
interval time.Duration | ||
store ScidStore | ||
} | ||
|
||
func NewScidCleaner( | ||
store ScidStore, | ||
interval time.Duration, | ||
) *ScidCleaner { | ||
return &ScidCleaner{ | ||
interval: interval, | ||
store: store, | ||
} | ||
} | ||
|
||
func (s *ScidCleaner) Start(ctx context.Context) error { | ||
ticker := time.NewTicker(s.interval) | ||
defer ticker.Stop() | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return ctx.Err() | ||
case t := <-ticker.C: | ||
err := s.store.RemoveExpired(ctx, t) | ||
if err != nil { | ||
log.Printf("Failed to remove expired scids: %v", err) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package lsps2 | ||
|
||
import ( | ||
"context" | ||
"crypto/rand" | ||
"fmt" | ||
"log" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/breez/lspd/basetypes" | ||
"github.com/breez/lspd/lightning" | ||
) | ||
|
||
const maxScidAttempts = 5 | ||
|
||
var two = big.NewInt(2) | ||
var sixtyfour = big.NewInt(64) | ||
var maxUint64 = two.Exp(two, sixtyfour, nil) | ||
|
||
func newScid() (*basetypes.ShortChannelID, error) { | ||
s, err := rand.Int(rand.Reader, maxUint64) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
scid := basetypes.ShortChannelID(s.Uint64()) | ||
return &scid, nil | ||
} | ||
|
||
type ScidService struct { | ||
store ScidStore | ||
cache lightning.ScidCacheReader | ||
} | ||
|
||
func NewScidService( | ||
store ScidStore, | ||
cache lightning.ScidCacheReader, | ||
) *ScidService { | ||
return &ScidService{store: store, cache: cache} | ||
} | ||
|
||
func (s *ScidService) ReserveNewScid( | ||
ctx context.Context, | ||
expiry time.Time, | ||
) (*basetypes.ShortChannelID, error) { | ||
for attempts := 0; attempts < maxScidAttempts; attempts++ { | ||
scid, err := newScid() | ||
if err != nil { | ||
log.Printf("NewScid() error: %v", err) | ||
continue | ||
} | ||
|
||
if s.cache.ContainsScid(*scid) { | ||
log.Printf( | ||
"Collision with existing channel when generating new scid %s", | ||
scid.ToString(), | ||
) | ||
continue | ||
} | ||
|
||
err = s.store.AddScid(ctx, *scid, expiry) | ||
if err == ErrScidExists { | ||
log.Printf( | ||
"Collision on inserting random new scid %s", | ||
scid.ToString(), | ||
) | ||
continue | ||
} | ||
|
||
if err != nil { | ||
return nil, fmt.Errorf("failed to insert scid reservation: %w", err) | ||
} | ||
|
||
return scid, nil | ||
} | ||
|
||
return nil, fmt.Errorf( | ||
"failed to reserve scid after %v attempts", | ||
maxScidAttempts, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package lsps2 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/breez/lspd/basetypes" | ||
) | ||
|
||
var ErrScidExists = fmt.Errorf("scid already exists") | ||
|
||
type ScidStore interface { | ||
AddScid( | ||
ctx context.Context, | ||
scid basetypes.ShortChannelID, | ||
expiry time.Time, | ||
) error | ||
RemoveExpired(ctx context.Context, before time.Time) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
DROP INDEX scid_reservations_expiry_idx; | ||
DROP TABLE public.scid_reservations; |
Oops, something went wrong.