Skip to content

Commit

Permalink
feat: enable VSS for new hubs with alby subscription (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz committed Nov 6, 2024
1 parent 42331ab commit 3fed364
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ FRONTEND_URL=http://localhost:5173
#LND_CERT_FILE=/home/YOUR_USERNAME/.polar/networks/1/volumes/lnd/alice/tls.cert
#LND_ADDRESS=127.0.0.1:10001
#LND_MACAROON_FILE=/home/YOUR_USERNAME/.polar/networks/1/volumes/lnd/alice/data/chain/bitcoin/regtest/admin.macaroon

#LDK_VSS_URL="http://localhost:8090/vss"
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Go to the [Deploy it yourself](#deploy-it-yourself) section below.

## Supported Backends

By default Alby Hub uses the embedded LDK based lightning node. Optionally it can be configured to use an external node:
By default Alby Hub uses the embedded LDK based lightning node. Optionally it can be configured to use an external node:

- LND
- Phoenixd
Expand All @@ -41,6 +41,7 @@ By default Alby Hub uses the embedded LDK based lightning node. Optionally it ca
- Yarn

### Environment setup

$ cp .env.example .env
# edit the config for your needs (Read further down for all the available env options)
$ vim .env
Expand Down Expand Up @@ -163,6 +164,7 @@ _To configure via env, the following parameters must be provided:_
### LDK Backend parameters

- `LDK_ESPLORA_SERVER`: By default the optimized Alby esplora is used. You can configure your own esplora server (note: the public blockstream one is slow and can cause onchain syncing and issues with opening channels)
- `LDK_VSS_URL`: Use VSS (encrypted remote storage) rather than local sqlite store for lightning and bitcoin data. Currently this feature only works for brand new Alby Hub instances that are connected to Alby Accounts with an active subscription plan.

#### LDK Network Configuration

Expand Down Expand Up @@ -362,7 +364,6 @@ Go to the [Quick start script](https://github.com/getAlby/hub/tree/master/script

Go to the [Quick start script](https://github.com/getAlby/hub/blob/master/scripts/pi-aarch64) which you can run as a service.


#### Quick start (Raspberry PI Zero)

Go to the [Quick start script](https://github.com/getAlby/hub/tree/master/scripts/pi-arm) which you can run as a service.
Expand Down
38 changes: 38 additions & 0 deletions alby/alby_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,44 @@ func (svc *albyOAuthService) GetInfo(ctx context.Context) (*AlbyInfo, error) {
}, nil
}

func (svc *albyOAuthService) GetVssToken(ctx context.Context) (string, error) {
token, err := svc.fetchUserToken(ctx)
if err != nil {
logger.Logger.WithError(err).Error("Failed to fetch user token")
return "", err
}

client := svc.oauthConf.Client(ctx, token)

req, err := http.NewRequest("GET", fmt.Sprintf("%s/internal/users/vss", albyOAuthAPIURL), nil)
if err != nil {
logger.Logger.WithError(err).Error("Error creating request for vss endpoint")
return "", err
}

setDefaultRequestHeaders(req)

res, err := client.Do(req)
if err != nil {
logger.Logger.WithError(err).Error("Failed to fetch vss endpoint")
return "", err
}

type vssTokenResponse struct {
Token string `json:"token"`
}

vssResponse := &vssTokenResponse{}
err = json.NewDecoder(res.Body).Decode(vssResponse)
if err != nil {
logger.Logger.WithError(err).Error("Failed to decode API response")
return "", err
}

logger.Logger.WithFields(logrus.Fields{"vssTokenResponse": vssResponse}).Info("Alby vss response")
return vssResponse.Token, nil
}

func (svc *albyOAuthService) GetMe(ctx context.Context) (*AlbyMe, error) {
token, err := svc.fetchUserToken(ctx)
if err != nil {
Expand Down
26 changes: 17 additions & 9 deletions alby/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type AlbyOAuthService interface {
DrainSharedWallet(ctx context.Context, lnClient lnclient.LNClient) error
UnlinkAccount(ctx context.Context) error
RequestAutoChannel(ctx context.Context, lnClient lnclient.LNClient, isPublic bool) (*AutoChannelResponse, error)
GetVssToken(ctx context.Context) (string, error)
}

type AlbyBalanceResponse struct {
Expand Down Expand Up @@ -61,16 +62,23 @@ type AlbyInfo struct {
type AlbyMeHub struct {
Name string `json:"name"`
}

type AlbyMeSubscription struct {
// PlanCode string `json:"plan_code"`
Buzz bool `json:"buzz"`
}

type AlbyMe struct {
Identifier string `json:"identifier"`
NPub string `json:"nostr_pubkey"`
LightningAddress string `json:"lightning_address"`
Email string `json:"email"`
Name string `json:"name"`
Avatar string `json:"avatar"`
KeysendPubkey string `json:"keysend_pubkey"`
SharedNode bool `json:"shared_node"`
Hub AlbyMeHub `json:"hub"`
Identifier string `json:"identifier"`
NPub string `json:"nostr_pubkey"`
LightningAddress string `json:"lightning_address"`
Email string `json:"email"`
Name string `json:"name"`
Avatar string `json:"avatar"`
KeysendPubkey string `json:"keysend_pubkey"`
SharedNode bool `json:"shared_node"`
Hub AlbyMeHub `json:"hub"`
Subscription AlbyMeSubscription `json:"subscription"`
}

type AlbyBalance struct {
Expand Down
1 change: 1 addition & 0 deletions config/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type AppConfig struct {
LDKEsploraServer string `envconfig:"LDK_ESPLORA_SERVER" default:"https://electrs.getalbypro.com"` // TODO: remove LDK prefix
LDKGossipSource string `envconfig:"LDK_GOSSIP_SOURCE"`
LDKLogLevel string `envconfig:"LDK_LOG_LEVEL" default:"3"`
LDKVssUrl string `envconfig:"LDK_VSS_URL"`
MempoolApi string `envconfig:"MEMPOOL_API" default:"https://mempool.space/api"`
AlbyClientId string `envconfig:"ALBY_OAUTH_CLIENT_ID" default:"J2PbXS1yOf"`
AlbyClientSecret string `envconfig:"ALBY_OAUTH_CLIENT_SECRET" default:"rABK2n16IWjLTZ9M1uKU"`
Expand Down
15 changes: 13 additions & 2 deletions lnclient/ldk/ldk.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ type LDKService struct {

const resetRouterKey = "ResetRouter"

func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events.EventPublisher, mnemonic, workDir string, network string, staticChannelsBackup *events.StaticChannelsBackupEvent, restoredFromSeed bool) (result lnclient.LNClient, err error) {
// TODO: remove staticChannelsBackup *events.StaticChannelsBackupEvent, restoredFromSeed bool (we have a dedicated SCB recovery tool)
func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events.EventPublisher, mnemonic, workDir string, network string, staticChannelsBackup *events.StaticChannelsBackupEvent, restoredFromSeed bool, vssToken string) (result lnclient.LNClient, err error) {
if mnemonic == "" || workDir == "" {
return nil, errors.New("one or more required LDK configuration are missing")
}
Expand Down Expand Up @@ -126,7 +127,17 @@ func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events
builder.RestoreEncodedChannelMonitors(getEncodedChannelMonitorsFromStaticChannelsBackup(staticChannelsBackup))
}

node, err := builder.Build()
logger.Logger.WithFields(logrus.Fields{
"vss_token": vssToken,
}).Info("Creating node")
var node *ldk_node.Node
if vssToken != "" {
node, err = builder.BuildWithVssStoreAndFixedHeaders(cfg.GetEnv().LDKVssUrl, "albyhub", map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", vssToken),
})
} else {
node, err = builder.Build()
}

if err != nil {
logger.Logger.Errorf("Failed to create LDK node: %v", err)
Expand Down
38 changes: 35 additions & 3 deletions service/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,42 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e
LNDMacaroonHex, _ := svc.cfg.Get("LNDMacaroonHex", encryptionKey)
lnClient, err = lnd.NewLNDService(ctx, svc.eventPublisher, LNDAddress, LNDCertHex, LNDMacaroonHex)
case config.LDKBackendType:
Mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey)
LDKWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "ldk")
mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey)
ldkWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "ldk")

nodeLastStartTime, _ := svc.cfg.Get("NodeLastStartTime", "")

// for brand new nodes, consider enabling VSS
if nodeLastStartTime == "" {
albyUserIdentifier, err := svc.albyOAuthSvc.GetUserIdentifier()
if err != nil {
logger.Logger.WithError(err).Error("Failed to fetch alby user identifier")
return err
}
if albyUserIdentifier != "" {
me, err := svc.albyOAuthSvc.GetMe(ctx)
if err != nil {
logger.Logger.WithError(err).Error("Failed to fetch alby user")
return err
}
// only activate VSS for Alby paid subscribers
if me.Subscription.Buzz {
svc.cfg.SetUpdate("LdkVssEnabled", "true", "")
}
}
}

vssToken := ""
vssEnabled, _ := svc.cfg.Get("LdkVssEnabled", "")
if vssEnabled == "true" {
vssToken, err = svc.albyOAuthSvc.GetVssToken(ctx)
if err != nil {
logger.Logger.WithError(err).Error("Failed to fetch VSS JWT token")
return err
}
}

lnClient, err = ldk.NewLDKService(ctx, svc.cfg, svc.eventPublisher, Mnemonic, LDKWorkdir, svc.cfg.GetEnv().LDKNetwork, nil, false)
lnClient, err = ldk.NewLDKService(ctx, svc.cfg, svc.eventPublisher, mnemonic, ldkWorkdir, svc.cfg.GetEnv().LDKNetwork, nil, false, vssToken)
case config.GreenlightBackendType:
Mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey)
GreenlightInviteCode, _ := svc.cfg.Get("GreenlightInviteCode", encryptionKey)
Expand Down

0 comments on commit 3fed364

Please sign in to comment.