Skip to content

Commit

Permalink
lwk: add TLS support for Electrum
Browse files Browse the repository at this point in the history
Add TLS support for Electrum.
In default, the scheme is a tls connection,
which allows connection to electrs.
context timeout for wallet operations to enhance reliability.
  • Loading branch information
YusukeShimizu committed May 13, 2024
1 parent 103c4f5 commit a2bef11
Show file tree
Hide file tree
Showing 13 changed files with 376 additions and 175 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,4 @@ mockgen: mockgen/lwk

.PHONY: mockgen/lwk
mockgen/lwk:
$(TOOLS_DIR)/bin/mockgen -source=lwk/electrumRPC.go -destination=lwk/mock/electrumRPC.go
$(TOOLS_DIR)/bin/mockgen -source=electrum/electrum.go -destination=electrum/mock/electrum.go
14 changes: 5 additions & 9 deletions cmd/peerswap-plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"path/filepath"
"time"

"github.com/checksum0/go-electrum/electrum"
"github.com/elementsproject/peerswap/elements"
"github.com/elementsproject/peerswap/isdev"
"github.com/elementsproject/peerswap/log"
Expand Down Expand Up @@ -209,22 +208,19 @@ func run(ctx context.Context, lightningPlugin *clightning.ClightningClient) erro
log.Infof("Liquid swaps enabled")
} else if config.LWK != nil && config.LWK.Enabled() {
liquidEnabled = true
ec, err2 := electrum.NewClientTCP(ctx, config.LWK.GetElectrumEndpoint())
lc, err2 := lwk.NewLWKRpcWallet(ctx, config.LWK)
if err2 != nil {
return err2
}
liquidRpcWallet, err2 = lwk.NewLWKRpcWallet(lwk.NewLwk(config.LWK.GetLWKEndpoint()),
ec, config.LWK.GetWalletName(), config.LWK.GetSignerName())
if err2 != nil {
return err2
}
liquidTxWatcher, err = lwk.NewElectrumTxWatcher(ec)
liquidTxWatcher, err = lwk.NewElectrumTxWatcher(lc.GetElectrumClient())
if err != nil {
return err
}
liquidRpcWallet = lc
liquidOnChainService = onchain.NewLiquidOnChain(liquidRpcWallet, config.LWK.GetChain())
supportedAssets = append(supportedAssets, "lbtc")
log.Infof("Liquid swaps enabled")
log.Infof("Liquid swaps enabled with LWK. Network: %s, wallet: %s",
config.LWK.GetNetwork(), config.LWK.GetWalletName())
} else {
log.Infof("Liquid swaps disabled")
}
Expand Down
16 changes: 5 additions & 11 deletions cmd/peerswaplnd/peerswapd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"syscall"
"time"

"github.com/checksum0/go-electrum/electrum"
"github.com/elementsproject/peerswap/elements"
"github.com/elementsproject/peerswap/isdev"
"github.com/elementsproject/peerswap/lnd"
Expand Down Expand Up @@ -231,22 +230,17 @@ func run() error {
liquidOnChainService = onchain.NewLiquidOnChain(liquidRpcWallet, liquidChain)
} else if cfg.LWKConfig.Enabled() {
log.Infof("Liquid swaps enabled with LWK. Network: %s, wallet: %s", cfg.LWKConfig.GetNetwork(), cfg.LWKConfig.GetWalletName())
ec, err := electrum.NewClientTCP(ctx, cfg.LWKConfig.GetElectrumEndpoint())
if err != nil {
return err
}

// This call is blocking, waiting for elements to come alive and sync.
liquidRpcWallet, err = lwk.NewLWKRpcWallet(lwk.NewLwk(cfg.LWKConfig.GetLWKEndpoint()),
ec, cfg.LWKConfig.GetWalletName(), cfg.LWKConfig.GetSignerName())
if err != nil {
return err
lc, err2 := lwk.NewLWKRpcWallet(ctx, cfg.LWKConfig)
if err2 != nil {
return err2
}
cfg.LiquidEnabled = true
liquidTxWatcher, err = lwk.NewElectrumTxWatcher(ec)
liquidTxWatcher, err = lwk.NewElectrumTxWatcher(lc.GetElectrumClient())
if err != nil {
return err
}
liquidRpcWallet = lc
liquidOnChainService = onchain.NewLiquidOnChain(liquidRpcWallet, cfg.LWKConfig.GetChain())
supportedAssets = append(supportedAssets, "lbtc")
} else {
Expand Down
86 changes: 86 additions & 0 deletions electrum/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package electrum

import (
"context"
"crypto/tls"

"github.com/checksum0/go-electrum/electrum"
"github.com/elementsproject/peerswap/log"
)

type electrumClient struct {
client *electrum.Client
endpoint string
isTLS bool
}

func NewElectrumClient(ctx context.Context, endpoint string, isTLS bool) (RPC, error) {
ec, err := newClient(ctx, endpoint, isTLS)
if err != nil {
return nil, err
}
client := &electrumClient{
client: ec,
endpoint: endpoint,
isTLS: isTLS,
}
return client, nil
}

// reconnect reconnects to the electrum server if the connection is lost.
func (c *electrumClient) reconnect(ctx context.Context) error {
if err := c.client.Ping(ctx); err != nil {
log.Infof("failed to ping electrum server: %v", err)
log.Infof("reconnecting to electrum server")
client, err := newClient(ctx, c.endpoint, c.isTLS)
if err != nil {
return err
}
c.client = client
}
return nil
}

func newClient(ctx context.Context, endpoint string, isTLS bool) (*electrum.Client, error) {
if isTLS {
return electrum.NewClientSSL(ctx, endpoint, &tls.Config{
MinVersion: tls.VersionTLS12,
})
}
return electrum.NewClientTCP(ctx, endpoint)
}

func (c *electrumClient) SubscribeHeaders(ctx context.Context) (<-chan *electrum.SubscribeHeadersResult, error) {
if err := c.reconnect(ctx); err != nil {
return nil, err
}
return c.client.SubscribeHeaders(ctx)
}

func (c *electrumClient) GetHistory(ctx context.Context, scripthash string) ([]*electrum.GetMempoolResult, error) {
if err := c.reconnect(ctx); err != nil {
return nil, err
}
return c.client.GetHistory(ctx, scripthash)
}

func (c *electrumClient) GetRawTransaction(ctx context.Context, txHash string) (string, error) {
if err := c.reconnect(ctx); err != nil {
return "", err
}
return c.client.GetRawTransaction(ctx, txHash)
}

func (c *electrumClient) BroadcastTransaction(ctx context.Context, rawTx string) (string, error) {
if err := c.reconnect(ctx); err != nil {
return "", err
}
return c.client.BroadcastTransaction(ctx, rawTx)
}

func (c *electrumClient) GetFee(ctx context.Context, target uint32) (float32, error) {
if err := c.reconnect(ctx); err != nil {
return 0, err
}
return c.client.GetFee(ctx, target)
}
2 changes: 2 additions & 0 deletions electrum/electrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ type RPC interface {
SubscribeHeaders(ctx context.Context) (<-chan *electrum.SubscribeHeadersResult, error)
GetHistory(ctx context.Context, scripthash string) ([]*electrum.GetMempoolResult, error)
GetRawTransaction(ctx context.Context, txHash string) (string, error)
BroadcastTransaction(ctx context.Context, rawTx string) (string, error)
GetFee(ctx context.Context, target uint32) (float32, error)
}
116 changes: 116 additions & 0 deletions electrum/mock/electrum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions lwk/conf_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ func (b *confBuilder) DefaultConf() (*confBuilder, error) {
switch b.network {
case NetworkTestnet:
lwkEndpoint = "http://localhost:32111"
electrumEndpoint = "tcp://blockstream.info:465"
electrumEndpoint = "ssl://blockstream.info:465"
case NetworkRegtest:
lwkEndpoint = "http://localhost:32112"
electrumEndpoint = "tcp://localhost:60401"
default:
// mainnet is the default port
lwkEndpoint = "http://localhost:32110"
electrumEndpoint = "tcp://blockstream.info:995"
electrumEndpoint = "ssl://blockstream.info:995"
}
lwkURL, err := NewConfURL(lwkEndpoint)
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions lwk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func (c *Conf) GetElectrumEndpoint() string {
return c.electrumEndpoint.Host
}

func (c *Conf) IsElectrumWithTLS() bool {
return c.electrumEndpoint.Scheme == "ssl"
}

func (c *Conf) GetNetwork() string {
return c.network.String()
}
Expand All @@ -53,6 +57,19 @@ func (c *Conf) GetChain() *network.Network {
}
}

func (c *Conf) GetAssetID() string {
switch c.network {
case NetworkMainnet:
return network.Liquid.AssetID
case NetworkRegtest:
return network.Regtest.AssetID
case NetworkTestnet:
return network.Testnet.AssetID
default:
return network.Testnet.AssetID
}
}

func (c *Conf) Enabled() bool {
return Validate(
c.electrumEndpoint,
Expand Down
Loading

0 comments on commit a2bef11

Please sign in to comment.