Skip to content

Commit

Permalink
cln+lnd: liveness check
Browse files Browse the repository at this point in the history
add a plugin hook in the case of core lightning and
an interceptor in the case of lnd, and pre-install
a dead/alive monitor for each daemon.
  • Loading branch information
YusukeShimizu committed Jun 12, 2024
1 parent 3d45569 commit 7f8e125
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 4 deletions.
73 changes: 73 additions & 0 deletions clightning/clightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
log2 "log"
Expand Down Expand Up @@ -131,6 +132,7 @@ func NewClightningClient(ctx context.Context) (*ClightningClient, <-chan interfa
cl.Plugin = glightning.NewPlugin(cl.onInit)
err := cl.Plugin.RegisterHooks(&glightning.Hooks{
CustomMsgReceived: cl.OnCustomMsg,
RpcCommand: cl.OnRPCCommand,
})
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -408,6 +410,77 @@ func (cl *ClightningClient) OnCustomMsg(event *glightning.CustomMsgReceivedEvent
return event.Continue(), nil
}

type Message struct {
Message string `json:"message"`
}

func (cl *ClightningClient) OnRPCCommand(event *glightning.RpcCommandEvent) (*glightning.RpcCommandResponse, error) {
if cl.gbitcoin != nil {
ok, err := cl.gbitcoin.Ping()
if err != nil || !ok {
return event.ReturnResult(&Message{Message: "bitcoin daemon unavailable"})
}
}

if cl.liquidWallet != nil {
ok, err := cl.liquidWallet.Ping()
if err != nil || !ok {
return event.ReturnError("liquid unavailable", -1)
}
}
return event.Continue(), nil
}

type LiquidBackendUnavailableResponse struct {
Result struct {
Message struct {
Liquid string `json:"liquid"`
} `json:"message"`
} `json:"result"`
}

func ReturnMessage(message string) *glightning.RpcCommandResponse {
// type Resp struct {
// Message string `json:"message"`
// }
// result := &struct {
// Result Resp `json:"result"`
// }{
// Result: Resp{
// Message: message,
// },
// }
type ResultMessage struct {
Result struct {
Message struct {
Liquid string `json:"liquid"`
} `json:"message"`
} `json:"result"`
}

var resultMessage = ResultMessage{
Result: struct {
Message struct {
Liquid string `json:"liquid"`
} `json:"message"`
}{
Message: struct {
Liquid string `json:"liquid"`
}{
Liquid: "liquid backend is not available",
},
},
}
marshaled, err := json.Marshal(resultMessage)
if err != nil {
log.Debugf("could not marshal message: %v", err)
}
log.Debugf("returning message: %s", marshaled)
return &glightning.RpcCommandResponse{
ReturnObj: marshaled,
}
}

// AddMessageHandler adds a listener for incoming peermessages
func (cl *ClightningClient) AddMessageHandler(f func(peerId string, msgType string, payload []byte) error) {
cl.msgHandlers = append(cl.msgHandlers, f)
Expand Down
19 changes: 18 additions & 1 deletion cmd/peerswaplnd/peerswapd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,9 @@ func run() error {
}
defer lis.Close()

grpcSrv := grpc.NewServer()
grpcSrv := grpc.NewServer(
grpc.UnaryInterceptor(livenessCheckInterceptor(liquidRpcWallet)),
)

peerswaprpc.RegisterPeerSwapServer(grpcSrv, peerswaprpcServer)

Expand Down Expand Up @@ -439,6 +441,21 @@ func run() error {
return nil
}

func livenessCheckInterceptor(liquidWallet wallet.Wallet) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if liquidWallet != nil {
ok, err := liquidWallet.Ping()
if err != nil {
return nil, fmt.Errorf("liquid backend not reachable: %v", err)
}
if !ok {
return nil, errors.New("liquid backend not reachable")
}
}
return handler(ctx, req)
}
}

func getBitcoinChain(ctx context.Context, li lnrpc.LightningClient) (*chaincfg.Params, error) {
gi, err := li.GetInfo(ctx, &lnrpc.GetInfoRequest{})
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions electrum/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,7 @@ func (c *electrumClient) GetFee(ctx context.Context, target uint32) (float32, er
}
return c.client.GetFee(ctx, target)
}

func (c *electrumClient) Ping(ctx context.Context) error {
return c.reconnect(ctx)
}
1 change: 1 addition & 0 deletions electrum/electrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ type RPC interface {
GetRawTransaction(ctx context.Context, txHash string) (string, error)
BroadcastTransaction(ctx context.Context, rawTx string) (string, error)
GetFee(ctx context.Context, target uint32) (float32, error)
Ping(ctx context.Context) error
}
14 changes: 14 additions & 0 deletions electrum/mock/electrum.go

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

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require (
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
github.com/btcsuite/winsvc v1.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.4.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down
11 changes: 11 additions & 0 deletions lwk/lwkwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,14 @@ func (r *LWKRpcWallet) SetLabel(txID, address, label string) error {
// TODO: call set label
return nil
}

func (r *LWKRpcWallet) Ping() (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
defer cancel()
_, err := r.lwkClient.version(ctx)
if err != nil {
return false, errors.New("lwk connection failed: " + err.Error())
}
err = r.electrumClient.Ping(ctx)
return err == nil, err
}
5 changes: 5 additions & 0 deletions wallet/elementsrpcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type RpcClient interface {
SendRawTx(txHex string) (string, error)
EstimateFee(blocks uint32, mode string) (*gelements.FeeResponse, error)
SetLabel(address, label string) error
Ping() (bool, error)
}

// ElementsRpcWallet uses the elementsd rpc wallet
Expand Down Expand Up @@ -191,3 +192,7 @@ func satsToAmountString(sats uint64) string {
bitcoinAmt := float64(sats) / 100000000
return fmt.Sprintf("%f", bitcoinAmt)
}

func (r *ElementsRpcWallet) Ping() (bool, error) {
return r.rpcClient.Ping()
}
1 change: 1 addition & 0 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ type Wallet interface {
SendRawTx(rawTx string) (txid string, err error)
GetFee(txSize int64) (uint64, error)
SetLabel(txID, address, label string) error
Ping() (bool, error)
}

0 comments on commit 7f8e125

Please sign in to comment.