mirror of
https://github.com/aljazceru/lspd.git
synced 2025-12-21 15:54:25 +01:00
use internal cln id as correlation id
This commit is contained in:
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -10,7 +11,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/breez/lspd/cln_plugin"
|
"github.com/breez/lspd/cln_plugin/proto"
|
||||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
@@ -24,7 +25,7 @@ import (
|
|||||||
type ClnHtlcInterceptor struct {
|
type ClnHtlcInterceptor struct {
|
||||||
pluginAddress string
|
pluginAddress string
|
||||||
client *ClnClient
|
client *ClnClient
|
||||||
pluginClient cln_plugin.ClnPluginClient
|
pluginClient proto.ClnPluginClient
|
||||||
initWg sync.WaitGroup
|
initWg sync.WaitGroup
|
||||||
doneWg sync.WaitGroup
|
doneWg sync.WaitGroup
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -51,7 +52,7 @@ func (i *ClnHtlcInterceptor) Start() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
i.pluginClient = cln_plugin.NewClnPluginClient(conn)
|
i.pluginClient = proto.NewClnPluginClient(conn)
|
||||||
i.ctx = ctx
|
i.ctx = ctx
|
||||||
i.cancel = cancel
|
i.cancel = cancel
|
||||||
return i.intercept()
|
return i.intercept()
|
||||||
@@ -111,7 +112,7 @@ func (i *ClnHtlcInterceptor) intercept() error {
|
|||||||
request.Htlc,
|
request.Htlc,
|
||||||
request.Onion.ShortChannelId,
|
request.Onion.ShortChannelId,
|
||||||
request.Htlc.AmountMsat, //with fees
|
request.Htlc.AmountMsat, //with fees
|
||||||
request.Onion.ForwardAmountMsat,
|
request.Onion.ForwardMsat,
|
||||||
request.Htlc.CltvExpiryRelative,
|
request.Htlc.CltvExpiryRelative,
|
||||||
request.Htlc.CltvExpiry,
|
request.Htlc.CltvExpiry,
|
||||||
request.Htlc.PaymentHash,
|
request.Htlc.PaymentHash,
|
||||||
@@ -120,28 +121,25 @@ func (i *ClnHtlcInterceptor) intercept() error {
|
|||||||
|
|
||||||
i.doneWg.Add(1)
|
i.doneWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
interceptResult := intercept(request.Htlc.PaymentHash, request.Onion.ForwardAmountMsat, request.Htlc.CltvExpiry)
|
paymentHash, err := hex.DecodeString(request.Htlc.PaymentHash)
|
||||||
|
if err != nil {
|
||||||
|
interceptorClient.Send(i.defaultResolution(request))
|
||||||
|
i.doneWg.Done()
|
||||||
|
}
|
||||||
|
interceptResult := intercept(paymentHash, request.Onion.ForwardMsat, request.Htlc.CltvExpiry)
|
||||||
switch interceptResult.action {
|
switch interceptResult.action {
|
||||||
case INTERCEPT_RESUME_WITH_ONION:
|
case INTERCEPT_RESUME_WITH_ONION:
|
||||||
interceptorClient.Send(i.resumeWithOnion(request, interceptResult))
|
interceptorClient.Send(i.resumeWithOnion(request, interceptResult))
|
||||||
case INTERCEPT_FAIL_HTLC_WITH_CODE:
|
case INTERCEPT_FAIL_HTLC_WITH_CODE:
|
||||||
interceptorClient.Send(&cln_plugin.HtlcResolution{
|
interceptorClient.Send(
|
||||||
Correlationid: request.Correlationid,
|
i.failWithCode(request, interceptResult.failureCode),
|
||||||
Outcome: &cln_plugin.HtlcResolution_Fail{
|
)
|
||||||
Fail: &cln_plugin.HtlcFail{
|
|
||||||
FailureMessage: i.mapFailureCode(interceptResult.failureCode),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
case INTERCEPT_RESUME:
|
case INTERCEPT_RESUME:
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
interceptorClient.Send(&cln_plugin.HtlcResolution{
|
interceptorClient.Send(
|
||||||
Correlationid: request.Correlationid,
|
i.defaultResolution(request),
|
||||||
Outcome: &cln_plugin.HtlcResolution_Continue{
|
)
|
||||||
Continue: &cln_plugin.HtlcContinue{},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i.doneWg.Done()
|
i.doneWg.Done()
|
||||||
@@ -163,29 +161,51 @@ func (i *ClnHtlcInterceptor) WaitStarted() LightningClient {
|
|||||||
return i.client
|
return i.client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ClnHtlcInterceptor) resumeWithOnion(request *cln_plugin.HtlcAccepted, interceptResult interceptResult) *cln_plugin.HtlcResolution {
|
func (i *ClnHtlcInterceptor) resumeWithOnion(request *proto.HtlcAccepted, interceptResult interceptResult) *proto.HtlcResolution {
|
||||||
//decoding and encoding onion with alias in type 6 record.
|
//decoding and encoding onion with alias in type 6 record.
|
||||||
newPayload, err := encodePayloadWithNextHop(request.Onion.Payload, interceptResult.channelId)
|
payload, err := hex.DecodeString(request.Onion.Payload)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("resumeWithOnion: hex.DecodeString(%v) error: %v", request.Onion.Payload, err)
|
||||||
|
return i.failWithCode(request, FAILURE_TEMPORARY_CHANNEL_FAILURE)
|
||||||
|
}
|
||||||
|
newPayload, err := encodePayloadWithNextHop(payload, interceptResult.channelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("encodePayloadWithNextHop error: %v", err)
|
log.Printf("encodePayloadWithNextHop error: %v", err)
|
||||||
return &cln_plugin.HtlcResolution{
|
return i.failWithCode(request, FAILURE_TEMPORARY_CHANNEL_FAILURE)
|
||||||
Correlationid: request.Correlationid,
|
|
||||||
Outcome: &cln_plugin.HtlcResolution_Fail{
|
|
||||||
Fail: &cln_plugin.HtlcFail{
|
|
||||||
FailureMessage: i.mapFailureCode(FAILURE_TEMPORARY_CHANNEL_FAILURE),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chanId := lnwire.NewChanIDFromOutPoint(interceptResult.channelPoint)
|
newPayloadStr := hex.EncodeToString(newPayload)
|
||||||
|
|
||||||
|
chanId := lnwire.NewChanIDFromOutPoint(interceptResult.channelPoint).String()
|
||||||
log.Printf("forwarding htlc to the destination node and a new private channel was opened")
|
log.Printf("forwarding htlc to the destination node and a new private channel was opened")
|
||||||
return &cln_plugin.HtlcResolution{
|
return &proto.HtlcResolution{
|
||||||
Correlationid: request.Correlationid,
|
Correlationid: request.Correlationid,
|
||||||
Outcome: &cln_plugin.HtlcResolution_ContinueWith{
|
Outcome: &proto.HtlcResolution_Continue{
|
||||||
ContinueWith: &cln_plugin.HtlcContinueWith{
|
Continue: &proto.HtlcContinue{
|
||||||
ChannelId: chanId[:],
|
ForwardTo: &chanId,
|
||||||
Payload: newPayload,
|
Payload: &newPayloadStr,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ClnHtlcInterceptor) defaultResolution(request *proto.HtlcAccepted) *proto.HtlcResolution {
|
||||||
|
return &proto.HtlcResolution{
|
||||||
|
Correlationid: request.Correlationid,
|
||||||
|
Outcome: &proto.HtlcResolution_Continue{
|
||||||
|
Continue: &proto.HtlcContinue{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ClnHtlcInterceptor) failWithCode(request *proto.HtlcAccepted, code interceptFailureCode) *proto.HtlcResolution {
|
||||||
|
return &proto.HtlcResolution{
|
||||||
|
Correlationid: request.Correlationid,
|
||||||
|
Outcome: &proto.HtlcResolution_Fail{
|
||||||
|
Fail: &proto.HtlcFail{
|
||||||
|
Failure: &proto.HtlcFail_FailureMessage{
|
||||||
|
FailureMessage: i.mapFailureCode(code),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -237,16 +257,16 @@ func encodePayloadWithNextHop(payload []byte, channelId uint64) ([]byte, error)
|
|||||||
return newPayloadBuf.Bytes(), nil
|
return newPayloadBuf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ClnHtlcInterceptor) mapFailureCode(original interceptFailureCode) []byte {
|
func (i *ClnHtlcInterceptor) mapFailureCode(original interceptFailureCode) string {
|
||||||
switch original {
|
switch original {
|
||||||
case FAILURE_TEMPORARY_CHANNEL_FAILURE:
|
case FAILURE_TEMPORARY_CHANNEL_FAILURE:
|
||||||
return []byte{0x10, 0x07}
|
return "1007"
|
||||||
case FAILURE_TEMPORARY_NODE_FAILURE:
|
case FAILURE_TEMPORARY_NODE_FAILURE:
|
||||||
return []byte{0x20, 0x02}
|
return "2002"
|
||||||
case FAILURE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS:
|
case FAILURE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS:
|
||||||
return []byte{0x40, 0x0F}
|
return "400F"
|
||||||
default:
|
default:
|
||||||
log.Printf("Unknown failure code %v, default to temporary channel failure.", original)
|
log.Printf("Unknown failure code %v, default to temporary channel failure.", original)
|
||||||
return []byte{0x10, 0x07} // temporary channel failure
|
return "1007" // temporary channel failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
117
cln_plugin/cln_messages.go
Normal file
117
cln_plugin/cln_messages.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package cln_plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Id json.RawMessage `json:"id,omitempty"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
JsonRpc string `json:"jsonrpc"`
|
||||||
|
Params json.RawMessage `json:"params,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Id json.RawMessage `json:"id"`
|
||||||
|
JsonRpc string `json:"jsonrpc"`
|
||||||
|
Result Result `json:"result,omitempty"`
|
||||||
|
Error *RpcError `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result interface{}
|
||||||
|
|
||||||
|
type RpcError struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data json.RawMessage `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Manifest struct {
|
||||||
|
Options []Option `json:"options"`
|
||||||
|
RpcMethods []*RpcMethod `json:"rpcmethods"`
|
||||||
|
Dynamic bool `json:"dynamic"`
|
||||||
|
Subscriptions []string `json:"subscriptions,omitempty"`
|
||||||
|
Hooks []Hook `json:"hooks,omitempty"`
|
||||||
|
FeatureBits *FeatureBits `json:"featurebits,omitempty"`
|
||||||
|
NonNumericIds bool `json:"nonnumericids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Default *string `json:"default,omitempty"`
|
||||||
|
Multi *bool `json:"multi,omitempty"`
|
||||||
|
Deprecated *bool `json:"deprecated,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RpcMethod struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Usage string `json:"usage"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
LongDescription *string `json:"long_description,omitempty"`
|
||||||
|
Deprecated *bool `json:"deprecated,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hook struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Before []string `json:"before,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeatureBits struct {
|
||||||
|
Node *string `json:"node,omitempty"`
|
||||||
|
Init *string `json:"init,omitempty"`
|
||||||
|
Channel *string `json:"channel,omitempty"`
|
||||||
|
Invoice *string `json:"invoice,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitMessage struct {
|
||||||
|
Options map[string]interface{} `json:"options,omitempty"`
|
||||||
|
Configuration *InitConfiguration `json:"configuration,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitConfiguration struct {
|
||||||
|
LightningDir string `json:"lightning-dir"`
|
||||||
|
RpcFile string `json:"rpc-file"`
|
||||||
|
Startup bool `json:"startup"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
FeatureSet *FeatureBits `json:"feature_set"`
|
||||||
|
Proxy *Proxy `json:"proxy"`
|
||||||
|
TorV3Enabled bool `json:"torv3-enabled"`
|
||||||
|
AlwaysUseProxy bool `json:"always_use_proxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Proxy struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcAccepted struct {
|
||||||
|
Onion *Onion `json:"onion"`
|
||||||
|
Htlc *Htlc `json:"htlc"`
|
||||||
|
ForwardTo string `json:"forward_to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Onion struct {
|
||||||
|
Payload string `json:"payload"`
|
||||||
|
ShortChannelId string `json:"short_channel_id"`
|
||||||
|
ForwardMsat uint64 `json:"forward_msat"`
|
||||||
|
OutgoingCltvValue uint32 `json:"outgoing_cltv_value"`
|
||||||
|
SharedSecret string `json:"shared_secret"`
|
||||||
|
NextOnion string `json:"next_onion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Htlc struct {
|
||||||
|
ShortChannelId string `json:"short_channel_id"`
|
||||||
|
Id uint64 `json:"id"`
|
||||||
|
AmountMsat uint64 `json:"amount_msat"`
|
||||||
|
CltvExpiry uint32 `json:"cltv_expiry"`
|
||||||
|
CltvExpiryRelative uint32 `json:"cltv_expiry_relative"`
|
||||||
|
PaymentHash string `json:"payment_hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogNotification struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
@@ -1,110 +1,488 @@
|
|||||||
package cln_plugin
|
package cln_plugin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
"github.com/breez/lspd/basetypes"
|
const (
|
||||||
"github.com/niftynei/glightning/glightning"
|
SubscriberTimeoutOption = "lsp.subscribertimeout"
|
||||||
|
ListenAddressOption = "lsp.listen"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultSubscriberTimeout = "1m"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MaxIntakeBuffer = 500 * 1024 * 1023
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SpecVersion = "2.0"
|
||||||
|
ParseError = -32700
|
||||||
|
InvalidRequest = -32600
|
||||||
|
MethodNotFound = -32601
|
||||||
|
InvalidParams = -32603
|
||||||
|
InternalErr = -32603
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TwoNewLines = []byte("\n\n")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClnPlugin struct {
|
type ClnPlugin struct {
|
||||||
server *server
|
done chan struct{}
|
||||||
plugin *glightning.Plugin
|
server *server
|
||||||
|
in *os.File
|
||||||
|
out *bufio.Writer
|
||||||
|
writeMtx sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClnPlugin(server *server) *ClnPlugin {
|
func NewClnPlugin(in, out *os.File) *ClnPlugin {
|
||||||
c := &ClnPlugin{
|
c := &ClnPlugin{
|
||||||
server: server,
|
done: make(chan struct{}),
|
||||||
|
in: in,
|
||||||
|
out: bufio.NewWriter(out),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.plugin = glightning.NewPlugin(c.onInit)
|
|
||||||
c.plugin.RegisterHooks(&glightning.Hooks{
|
|
||||||
HtlcAccepted: c.onHtlcAccepted,
|
|
||||||
})
|
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClnPlugin) Start() error {
|
// Starts the cln plugin.
|
||||||
err := c.plugin.Start(os.Stdin, os.Stdout)
|
// NOTE: The grpc server is started in the handleInit function.
|
||||||
if err != nil {
|
func (c *ClnPlugin) Start() {
|
||||||
log.Printf("Plugin error: %v", err)
|
c.setupLogging()
|
||||||
return err
|
go c.listen()
|
||||||
}
|
<-c.done
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClnPlugin) Stop() {
|
func (c *ClnPlugin) setupLogging() {
|
||||||
c.plugin.Stop()
|
in, out := io.Pipe()
|
||||||
c.server.Stop()
|
go func(in io.Reader) {
|
||||||
}
|
// everytime we get a new message, log it thru c-lightning
|
||||||
|
scanner := bufio.NewScanner(in)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
if !scanner.Scan() {
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatalf(
|
||||||
|
"can't print out to std err, killing: %v",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClnPlugin) onInit(plugin *glightning.Plugin, options map[string]glightning.Option, config *glightning.Config) {
|
for _, line := range strings.Split(scanner.Text(), "\n") {
|
||||||
log.Printf("successfully init'd! %v\n", config.RpcFile)
|
c.log("info", line)
|
||||||
|
}
|
||||||
log.Printf("Starting htlc grpc server.")
|
}
|
||||||
go func() {
|
|
||||||
err := c.server.Start()
|
|
||||||
if err == nil {
|
|
||||||
log.Printf("WARNING server stopped.")
|
|
||||||
} else {
|
|
||||||
log.Printf("ERROR Server stopped with error: %v", err)
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
}(in)
|
||||||
|
log.SetFlags(log.Ltime | log.Lshortfile)
|
||||||
|
log.SetOutput(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClnPlugin) onHtlcAccepted(event *glightning.HtlcAcceptedEvent) (*glightning.HtlcAcceptedResponse, error) {
|
// Stops the cln plugin. Drops any remaining work immediately.
|
||||||
payload, err := hex.DecodeString(event.Onion.Payload)
|
// Pending htlcs will be replayed when cln starts again.
|
||||||
if err != nil {
|
func (c *ClnPlugin) Stop() {
|
||||||
log.Printf("ERROR failed to decode payload %s: %v", event.Onion.Payload, err)
|
close(c.done)
|
||||||
return nil, err
|
|
||||||
|
s := c.server
|
||||||
|
if s != nil {
|
||||||
|
s.Stop()
|
||||||
}
|
}
|
||||||
scid, err := basetypes.NewShortChannelIDFromString(event.Onion.ShortChannelId)
|
}
|
||||||
if err != nil {
|
|
||||||
log.Printf("ERROR failed to decode short channel id %s: %v", event.Onion.ShortChannelId, err)
|
// listens stdout for requests from cln and sends the requests to the
|
||||||
return nil, err
|
// appropriate handler in fifo order.
|
||||||
|
func (c *ClnPlugin) listen() error {
|
||||||
|
scanner := bufio.NewScanner(c.in)
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
scanner.Buffer(buf, MaxIntakeBuffer)
|
||||||
|
|
||||||
|
// cln messages are split by a double newline.
|
||||||
|
scanner.Split(scanDoubleNewline)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
if !scanner.Scan() {
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := scanner.Bytes()
|
||||||
|
// TODO: Pipe logs to the proper place.
|
||||||
|
log.Println(string(msg))
|
||||||
|
// pass down a copy so things stay sane
|
||||||
|
msg_buf := make([]byte, len(msg))
|
||||||
|
copy(msg_buf, msg)
|
||||||
|
|
||||||
|
// NOTE: processMsg is synchronous, so it should only do quick work.
|
||||||
|
c.processMsg(msg_buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ph, err := hex.DecodeString(event.Htlc.PaymentHash)
|
}
|
||||||
if err != nil {
|
|
||||||
log.Printf("ERROR failed to decode payment hash %s: %v", event.Onion.ShortChannelId, err)
|
// processes a single message from cln. Sends the message to the appropriate
|
||||||
return nil, err
|
// handler.
|
||||||
|
func (c *ClnPlugin) processMsg(msg []byte) {
|
||||||
|
if len(msg) == 0 {
|
||||||
|
c.sendError(nil, InvalidRequest, "Invalid Request")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := c.server.Send(&HtlcAccepted{
|
// Right now we don't handle arrays of requests...
|
||||||
Onion: &Onion{
|
if msg[0] == '[' {
|
||||||
Payload: payload,
|
var requests []*Request
|
||||||
ShortChannelId: uint64(*scid),
|
err := json.Unmarshal(msg, &requests)
|
||||||
ForwardAmountMsat: event.Onion.ForwardAmount,
|
if err != nil {
|
||||||
},
|
c.sendError(
|
||||||
Htlc: &HtlcOffer{
|
nil,
|
||||||
AmountMsat: event.Htlc.AmountMilliSatoshi,
|
ParseError,
|
||||||
CltvExpiryRelative: uint32(event.Htlc.CltvExpiryRelative),
|
fmt.Sprintf("Parse error:%s [%s]", err.Error(), msg),
|
||||||
CltvExpiry: uint32(event.Htlc.CltvExpiry),
|
)
|
||||||
PaymentHash: ph,
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, request := range requests {
|
||||||
|
c.processRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the received buffer into a request object.
|
||||||
|
var request Request
|
||||||
|
err := json.Unmarshal(msg, &request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to unmarshal request: %v", err)
|
||||||
|
c.sendError(
|
||||||
|
nil,
|
||||||
|
ParseError,
|
||||||
|
fmt.Sprintf("Parse error:%s [%s]", err.Error(), msg),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.processRequest(&request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClnPlugin) processRequest(request *Request) {
|
||||||
|
// Make sure the spec version is expected.
|
||||||
|
if request.JsonRpc != SpecVersion {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidRequest,
|
||||||
|
fmt.Sprintf(
|
||||||
|
`Invalid jsonrpc, expected '%s' got '%s'`,
|
||||||
|
SpecVersion,
|
||||||
|
request.JsonRpc,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the message to the appropriate handler.
|
||||||
|
switch request.Method {
|
||||||
|
case "getmanifest":
|
||||||
|
c.handleGetManifest(request)
|
||||||
|
case "init":
|
||||||
|
c.handleInit(request)
|
||||||
|
case "shutdown":
|
||||||
|
c.handleShutdown(request)
|
||||||
|
case "htlc_accepted":
|
||||||
|
c.handleHtlcAccepted(request)
|
||||||
|
default:
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
MethodNotFound,
|
||||||
|
fmt.Sprintf("Method '%s' not found", request.Method),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns this plugin's manifest to cln.
|
||||||
|
func (c *ClnPlugin) handleGetManifest(request *Request) {
|
||||||
|
c.sendToCln(&Response{
|
||||||
|
Id: request.Id,
|
||||||
|
JsonRpc: SpecVersion,
|
||||||
|
Result: &Manifest{
|
||||||
|
Options: []Option{
|
||||||
|
{
|
||||||
|
Name: ListenAddressOption,
|
||||||
|
Type: "string",
|
||||||
|
Description: "listen address for the htlc_accepted lsp " +
|
||||||
|
"grpc server",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: SubscriberTimeoutOption,
|
||||||
|
Type: "string",
|
||||||
|
Description: "htlc timeout duration when there is no " +
|
||||||
|
"subscriber to the grpc server. golang duration " +
|
||||||
|
"string.",
|
||||||
|
Default: &DefaultSubscriberTimeout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RpcMethods: []*RpcMethod{},
|
||||||
|
Dynamic: true,
|
||||||
|
Hooks: []Hook{
|
||||||
|
{
|
||||||
|
Name: "htlc_accepted",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NonNumericIds: true,
|
||||||
|
Subscriptions: []string{
|
||||||
|
"shutdown",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
_, ok := resp.Outcome.(*HtlcResolution_Continue)
|
|
||||||
if ok {
|
// Handles plugin initialization. Parses startup options and starts the grpc
|
||||||
return event.Continue(), nil
|
// server.
|
||||||
}
|
func (c *ClnPlugin) handleInit(request *Request) {
|
||||||
|
// Deserialize the init message.
|
||||||
cont, ok := resp.Outcome.(*HtlcResolution_ContinueWith)
|
var initMsg InitMessage
|
||||||
if ok {
|
err := json.Unmarshal(request.Params, &initMsg)
|
||||||
chanId := hex.EncodeToString(cont.ContinueWith.ChannelId)
|
if err != nil {
|
||||||
pl := hex.EncodeToString(cont.ContinueWith.Payload)
|
c.sendError(
|
||||||
return event.ContinueWith(chanId, pl), nil
|
request.Id,
|
||||||
}
|
ParseError,
|
||||||
|
fmt.Sprintf(
|
||||||
fail, ok := resp.Outcome.(*HtlcResolution_Fail)
|
"Error parsing init params:%s [%s]",
|
||||||
if ok {
|
err.Error(),
|
||||||
fm := hex.EncodeToString(fail.Fail.FailureMessage)
|
request.Params,
|
||||||
return event.Fail(fm), err
|
),
|
||||||
}
|
)
|
||||||
|
return
|
||||||
log.Printf("Unexpected htlc resolution type %T: %+v", resp.Outcome, resp.Outcome)
|
}
|
||||||
return event.Fail("1007"), nil // temporary channel failure
|
|
||||||
|
// Get the listen address option.
|
||||||
|
l, ok := initMsg.Options[ListenAddressOption]
|
||||||
|
if !ok {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidParams,
|
||||||
|
fmt.Sprintf("Missing option '%s'", ListenAddressOption),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, ok := l.(string)
|
||||||
|
if !ok || addr == "" {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidParams,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Invalid value '%v' for option '%s'",
|
||||||
|
l,
|
||||||
|
ListenAddressOption,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the subscriber timeout option.
|
||||||
|
t, ok := initMsg.Options[SubscriberTimeoutOption]
|
||||||
|
if !ok {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidParams,
|
||||||
|
fmt.Sprintf("Missing option '%s'", SubscriberTimeoutOption),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := t.(string)
|
||||||
|
if !ok || s == "" {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidParams,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Invalid value '%v' for option '%s'",
|
||||||
|
t,
|
||||||
|
SubscriberTimeoutOption,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriberTimeout, err := time.ParseDuration(s)
|
||||||
|
if err != nil {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InvalidParams,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Invalid value '%v' for option '%s'",
|
||||||
|
s,
|
||||||
|
SubscriberTimeoutOption,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the grpc server.
|
||||||
|
c.server = NewServer(addr, subscriberTimeout)
|
||||||
|
go c.server.Start()
|
||||||
|
err = c.server.WaitStarted()
|
||||||
|
if err != nil {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
InternalErr,
|
||||||
|
fmt.Sprintf("Failed to start server: %s", err.Error()),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for responses from the grpc server.
|
||||||
|
go c.listenServer()
|
||||||
|
|
||||||
|
// Let cln know the plugin is initialized.
|
||||||
|
c.sendToCln(&Response{
|
||||||
|
Id: request.Id,
|
||||||
|
JsonRpc: SpecVersion,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listens to responses to htlc_accepted requests from the grpc server.
|
||||||
|
func (c *ClnPlugin) listenServer() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
id, result := c.server.Receive()
|
||||||
|
|
||||||
|
// The server may return nil if it is stopped.
|
||||||
|
if result == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
serid, _ := json.Marshal(&id)
|
||||||
|
c.sendToCln(&Response{
|
||||||
|
Id: serid,
|
||||||
|
JsonRpc: SpecVersion,
|
||||||
|
Result: result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles the shutdown message. Stops any work immediately.
|
||||||
|
func (c *ClnPlugin) handleShutdown(request *Request) {
|
||||||
|
c.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a htlc_accepted message to the grpc server.
|
||||||
|
func (c *ClnPlugin) handleHtlcAccepted(request *Request) {
|
||||||
|
var htlc HtlcAccepted
|
||||||
|
err := json.Unmarshal(request.Params, &htlc)
|
||||||
|
if err != nil {
|
||||||
|
c.sendError(
|
||||||
|
request.Id,
|
||||||
|
ParseError,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Error parsing htlc_accepted params:%s [%s]",
|
||||||
|
err.Error(),
|
||||||
|
request.Params,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.server.Send(c.idToString(request.Id), &htlc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends an error to cln.
|
||||||
|
func (c *ClnPlugin) sendError(id json.RawMessage, code int, message string) {
|
||||||
|
resp := &Response{
|
||||||
|
JsonRpc: SpecVersion,
|
||||||
|
Error: &RpcError{
|
||||||
|
Code: code,
|
||||||
|
Message: message,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(id) > 0 {
|
||||||
|
resp.Id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
c.sendToCln(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts a raw cln id to string. The CLN id can either be an integer or a
|
||||||
|
// string. if it's a string, the quotes are removed.
|
||||||
|
func (c *ClnPlugin) idToString(id json.RawMessage) string {
|
||||||
|
if len(id) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
str := string(id)
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
str = strings.Trim(str, "\"")
|
||||||
|
str = strings.Trim(str, "'")
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a message to cln.
|
||||||
|
func (c *ClnPlugin) sendToCln(msg interface{}) {
|
||||||
|
c.writeMtx.Lock()
|
||||||
|
defer c.writeMtx.Unlock()
|
||||||
|
|
||||||
|
// TODO: log
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, TwoNewLines...)
|
||||||
|
c.out.Write(data)
|
||||||
|
c.out.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClnPlugin) log(level string, message string) {
|
||||||
|
params, _ := json.Marshal(&LogNotification{
|
||||||
|
Level: level,
|
||||||
|
Message: message,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.sendToCln(&Request{
|
||||||
|
Method: "log",
|
||||||
|
JsonRpc: SpecVersion,
|
||||||
|
Params: params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method for the bufio scanner to split messages on double newlines.
|
||||||
|
func scanDoubleNewline(
|
||||||
|
data []byte,
|
||||||
|
atEOF bool,
|
||||||
|
) (advance int, token []byte, err error) {
|
||||||
|
for i := 0; i < len(data); i++ {
|
||||||
|
if data[i] == '\n' && (i+1) < len(data) && data[i+1] == '\n' {
|
||||||
|
return i + 2, data[:i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this trashes anything left over in
|
||||||
|
// the buffer if we're at EOF, with no /n/n present
|
||||||
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,674 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.28.1
|
|
||||||
// protoc v3.21.8
|
|
||||||
// source: cln_plugin.proto
|
|
||||||
|
|
||||||
package cln_plugin
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type HtlcAccepted struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Correlationid uint64 `protobuf:"varint,1,opt,name=correlationid,proto3" json:"correlationid,omitempty"`
|
|
||||||
Onion *Onion `protobuf:"bytes,2,opt,name=onion,proto3" json:"onion,omitempty"`
|
|
||||||
Htlc *HtlcOffer `protobuf:"bytes,3,opt,name=htlc,proto3" json:"htlc,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) Reset() {
|
|
||||||
*x = HtlcAccepted{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcAccepted) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcAccepted.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcAccepted) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) GetCorrelationid() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Correlationid
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) GetOnion() *Onion {
|
|
||||||
if x != nil {
|
|
||||||
return x.Onion
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcAccepted) GetHtlc() *HtlcOffer {
|
|
||||||
if x != nil {
|
|
||||||
return x.Htlc
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Onion struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
|
||||||
ShortChannelId uint64 `protobuf:"varint,2,opt,name=short_channel_id,json=shortChannelId,proto3" json:"short_channel_id,omitempty"`
|
|
||||||
ForwardAmountMsat uint64 `protobuf:"varint,3,opt,name=forward_amount_msat,json=forwardAmountMsat,proto3" json:"forward_amount_msat,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Onion) Reset() {
|
|
||||||
*x = Onion{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Onion) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Onion) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Onion) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Onion.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Onion) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Onion) GetPayload() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Payload
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Onion) GetShortChannelId() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ShortChannelId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Onion) GetForwardAmountMsat() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ForwardAmountMsat
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcOffer struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
AmountMsat uint64 `protobuf:"varint,2,opt,name=amount_msat,json=amountMsat,proto3" json:"amount_msat,omitempty"`
|
|
||||||
CltvExpiryRelative uint32 `protobuf:"varint,3,opt,name=cltv_expiry_relative,json=cltvExpiryRelative,proto3" json:"cltv_expiry_relative,omitempty"`
|
|
||||||
CltvExpiry uint32 `protobuf:"varint,4,opt,name=cltv_expiry,json=cltvExpiry,proto3" json:"cltv_expiry,omitempty"`
|
|
||||||
PaymentHash []byte `protobuf:"bytes,5,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) Reset() {
|
|
||||||
*x = HtlcOffer{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcOffer) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[2]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcOffer.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcOffer) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) GetAmountMsat() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.AmountMsat
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) GetCltvExpiryRelative() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.CltvExpiryRelative
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) GetCltvExpiry() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.CltvExpiry
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcOffer) GetPaymentHash() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.PaymentHash
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcResolution struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Correlationid uint64 `protobuf:"varint,1,opt,name=correlationid,proto3" json:"correlationid,omitempty"`
|
|
||||||
// Types that are assignable to Outcome:
|
|
||||||
// *HtlcResolution_Fail
|
|
||||||
// *HtlcResolution_Continue
|
|
||||||
// *HtlcResolution_ContinueWith
|
|
||||||
Outcome isHtlcResolution_Outcome `protobuf_oneof:"outcome"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) Reset() {
|
|
||||||
*x = HtlcResolution{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcResolution) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcResolution.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcResolution) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) GetCorrelationid() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Correlationid
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *HtlcResolution) GetOutcome() isHtlcResolution_Outcome {
|
|
||||||
if m != nil {
|
|
||||||
return m.Outcome
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) GetFail() *HtlcFail {
|
|
||||||
if x, ok := x.GetOutcome().(*HtlcResolution_Fail); ok {
|
|
||||||
return x.Fail
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) GetContinue() *HtlcContinue {
|
|
||||||
if x, ok := x.GetOutcome().(*HtlcResolution_Continue); ok {
|
|
||||||
return x.Continue
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcResolution) GetContinueWith() *HtlcContinueWith {
|
|
||||||
if x, ok := x.GetOutcome().(*HtlcResolution_ContinueWith); ok {
|
|
||||||
return x.ContinueWith
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type isHtlcResolution_Outcome interface {
|
|
||||||
isHtlcResolution_Outcome()
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcResolution_Fail struct {
|
|
||||||
Fail *HtlcFail `protobuf:"bytes,2,opt,name=fail,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcResolution_Continue struct {
|
|
||||||
Continue *HtlcContinue `protobuf:"bytes,3,opt,name=continue,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcResolution_ContinueWith struct {
|
|
||||||
ContinueWith *HtlcContinueWith `protobuf:"bytes,4,opt,name=continue_with,json=continueWith,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcResolution_Fail) isHtlcResolution_Outcome() {}
|
|
||||||
|
|
||||||
func (*HtlcResolution_Continue) isHtlcResolution_Outcome() {}
|
|
||||||
|
|
||||||
func (*HtlcResolution_ContinueWith) isHtlcResolution_Outcome() {}
|
|
||||||
|
|
||||||
type HtlcFail struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
FailureMessage []byte `protobuf:"bytes,1,opt,name=failure_message,json=failureMessage,proto3" json:"failure_message,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcFail) Reset() {
|
|
||||||
*x = HtlcFail{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcFail) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcFail) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcFail) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[4]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcFail.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcFail) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcFail) GetFailureMessage() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.FailureMessage
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcContinue struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinue) Reset() {
|
|
||||||
*x = HtlcContinue{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[5]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinue) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcContinue) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcContinue) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[5]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcContinue.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcContinue) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{5}
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtlcContinueWith struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
ChannelId []byte `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
|
||||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinueWith) Reset() {
|
|
||||||
*x = HtlcContinueWith{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[6]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinueWith) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HtlcContinueWith) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HtlcContinueWith) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_cln_plugin_proto_msgTypes[6]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HtlcContinueWith.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HtlcContinueWith) Descriptor() ([]byte, []int) {
|
|
||||||
return file_cln_plugin_proto_rawDescGZIP(), []int{6}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinueWith) GetChannelId() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.ChannelId
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HtlcContinueWith) GetPayload() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Payload
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_cln_plugin_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_cln_plugin_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x10, 0x63, 0x6c, 0x6e, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x22, 0x72, 0x0a, 0x0c, 0x48, 0x74, 0x6c, 0x63, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
|
|
||||||
0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
|
|
||||||
0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65,
|
|
||||||
0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x05, 0x6f, 0x6e, 0x69, 0x6f,
|
|
||||||
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x52,
|
|
||||||
0x05, 0x6f, 0x6e, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x74, 0x6c, 0x63, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x4f, 0x66, 0x66, 0x65, 0x72,
|
|
||||||
0x52, 0x04, 0x68, 0x74, 0x6c, 0x63, 0x22, 0x7b, 0x0a, 0x05, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x12,
|
|
||||||
0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
|
||||||
0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x68, 0x6f,
|
|
||||||
0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
|
|
||||||
0x6c, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x61,
|
|
||||||
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
|
|
||||||
0x52, 0x11, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4d,
|
|
||||||
0x73, 0x61, 0x74, 0x22, 0xa2, 0x01, 0x0a, 0x09, 0x48, 0x74, 0x6c, 0x63, 0x4f, 0x66, 0x66, 0x65,
|
|
||||||
0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x73,
|
|
||||||
0x61, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72,
|
|
||||||
0x79, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
|
|
||||||
0x52, 0x12, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x52, 0x65, 0x6c, 0x61,
|
|
||||||
0x74, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70,
|
|
||||||
0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x45,
|
|
||||||
0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
|
||||||
0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79,
|
|
||||||
0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x48, 0x74, 0x6c,
|
|
||||||
0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x63,
|
|
||||||
0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x69,
|
|
||||||
0x64, 0x12, 0x1f, 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
|
||||||
0x09, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x46, 0x61, 0x69, 0x6c, 0x48, 0x00, 0x52, 0x04, 0x66, 0x61,
|
|
||||||
0x69, 0x6c, 0x12, 0x2b, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69,
|
|
||||||
0x6e, 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x12,
|
|
||||||
0x38, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68,
|
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x43, 0x6f, 0x6e,
|
|
||||||
0x74, 0x69, 0x6e, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x6f, 0x6e,
|
|
||||||
0x74, 0x69, 0x6e, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x75, 0x74,
|
|
||||||
0x63, 0x6f, 0x6d, 0x65, 0x22, 0x33, 0x0a, 0x08, 0x48, 0x74, 0x6c, 0x63, 0x46, 0x61, 0x69, 0x6c,
|
|
||||||
0x12, 0x27, 0x0a, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73,
|
|
||||||
0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75,
|
|
||||||
0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x0e, 0x0a, 0x0c, 0x48, 0x74, 0x6c,
|
|
||||||
0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x22, 0x4b, 0x0a, 0x10, 0x48, 0x74, 0x6c,
|
|
||||||
0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x12, 0x1d, 0x0a,
|
|
||||||
0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07,
|
|
||||||
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70,
|
|
||||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x32, 0x3d, 0x0a, 0x09, 0x43, 0x6c, 0x6e, 0x50, 0x6c, 0x75,
|
|
||||||
0x67, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x0a, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61,
|
|
||||||
0x6d, 0x12, 0x0f, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69,
|
|
||||||
0x6f, 0x6e, 0x1a, 0x0d, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
|
|
||||||
0x64, 0x28, 0x01, 0x30, 0x01, 0x42, 0x22, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x72, 0x65, 0x65, 0x7a, 0x2f, 0x6c, 0x73, 0x70, 0x64, 0x2f, 0x63,
|
|
||||||
0x6c, 0x6e, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_cln_plugin_proto_rawDescOnce sync.Once
|
|
||||||
file_cln_plugin_proto_rawDescData = file_cln_plugin_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_cln_plugin_proto_rawDescGZIP() []byte {
|
|
||||||
file_cln_plugin_proto_rawDescOnce.Do(func() {
|
|
||||||
file_cln_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_cln_plugin_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_cln_plugin_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_cln_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
|
||||||
var file_cln_plugin_proto_goTypes = []interface{}{
|
|
||||||
(*HtlcAccepted)(nil), // 0: HtlcAccepted
|
|
||||||
(*Onion)(nil), // 1: Onion
|
|
||||||
(*HtlcOffer)(nil), // 2: HtlcOffer
|
|
||||||
(*HtlcResolution)(nil), // 3: HtlcResolution
|
|
||||||
(*HtlcFail)(nil), // 4: HtlcFail
|
|
||||||
(*HtlcContinue)(nil), // 5: HtlcContinue
|
|
||||||
(*HtlcContinueWith)(nil), // 6: HtlcContinueWith
|
|
||||||
}
|
|
||||||
var file_cln_plugin_proto_depIdxs = []int32{
|
|
||||||
1, // 0: HtlcAccepted.onion:type_name -> Onion
|
|
||||||
2, // 1: HtlcAccepted.htlc:type_name -> HtlcOffer
|
|
||||||
4, // 2: HtlcResolution.fail:type_name -> HtlcFail
|
|
||||||
5, // 3: HtlcResolution.continue:type_name -> HtlcContinue
|
|
||||||
6, // 4: HtlcResolution.continue_with:type_name -> HtlcContinueWith
|
|
||||||
3, // 5: ClnPlugin.HtlcStream:input_type -> HtlcResolution
|
|
||||||
0, // 6: ClnPlugin.HtlcStream:output_type -> HtlcAccepted
|
|
||||||
6, // [6:7] is the sub-list for method output_type
|
|
||||||
5, // [5:6] is the sub-list for method input_type
|
|
||||||
5, // [5:5] is the sub-list for extension type_name
|
|
||||||
5, // [5:5] is the sub-list for extension extendee
|
|
||||||
0, // [0:5] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_cln_plugin_proto_init() }
|
|
||||||
func file_cln_plugin_proto_init() {
|
|
||||||
if File_cln_plugin_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_cln_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcAccepted); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Onion); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcOffer); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcResolution); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcFail); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcContinue); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*HtlcContinueWith); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cln_plugin_proto_msgTypes[3].OneofWrappers = []interface{}{
|
|
||||||
(*HtlcResolution_Fail)(nil),
|
|
||||||
(*HtlcResolution_Continue)(nil),
|
|
||||||
(*HtlcResolution_ContinueWith)(nil),
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_cln_plugin_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 7,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_cln_plugin_proto_goTypes,
|
|
||||||
DependencyIndexes: file_cln_plugin_proto_depIdxs,
|
|
||||||
MessageInfos: file_cln_plugin_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_cln_plugin_proto = out.File
|
|
||||||
file_cln_plugin_proto_rawDesc = nil
|
|
||||||
file_cln_plugin_proto_goTypes = nil
|
|
||||||
file_cln_plugin_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,31 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/breez/lspd/cln_plugin"
|
"github.com/breez/lspd/cln_plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
listen := os.Getenv("LISTEN_ADDRESS")
|
plugin := cln_plugin.NewClnPlugin(os.Stdin, os.Stdout)
|
||||||
server := cln_plugin.NewServer(listen)
|
plugin.Start()
|
||||||
plugin := cln_plugin.NewClnPlugin(server)
|
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGINT)
|
|
||||||
go func() {
|
|
||||||
sig := <-c
|
|
||||||
log.Printf("Received stop signal %v. Stopping.", sig)
|
|
||||||
plugin.Stop()
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := plugin.Start()
|
|
||||||
if err == nil {
|
|
||||||
log.Printf("cln plugin stopped.")
|
|
||||||
} else {
|
|
||||||
log.Printf("cln plugin stopped with error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
SCRIPTDIR=$(dirname $0)
|
SCRIPTDIR=$(dirname $0)
|
||||||
PROTO_ROOT=$SCRIPTDIR/proto
|
PROTO_ROOT=$SCRIPTDIR/proto
|
||||||
|
|
||||||
protoc --go_out=$SCRIPTDIR --go_opt=paths=source_relative --go-grpc_out=$SCRIPTDIR --go-grpc_opt=paths=source_relative -I=$PROTO_ROOT $PROTO_ROOT/*
|
protoc --go_out=$PROTO_ROOT --go_opt=paths=source_relative --go-grpc_out=$PROTO_ROOT --go-grpc_opt=paths=source_relative -I=$PROTO_ROOT $PROTO_ROOT/*.proto
|
||||||
787
cln_plugin/proto/cln_plugin.pb.go
Normal file
787
cln_plugin/proto/cln_plugin.pb.go
Normal file
@@ -0,0 +1,787 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.28.1
|
||||||
|
// protoc v3.21.12
|
||||||
|
// source: cln_plugin.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type HtlcAccepted struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Correlationid string `protobuf:"bytes,1,opt,name=correlationid,proto3" json:"correlationid,omitempty"`
|
||||||
|
Onion *Onion `protobuf:"bytes,2,opt,name=onion,proto3" json:"onion,omitempty"`
|
||||||
|
Htlc *Htlc `protobuf:"bytes,3,opt,name=htlc,proto3" json:"htlc,omitempty"`
|
||||||
|
ForwardTo string `protobuf:"bytes,4,opt,name=forward_to,json=forwardTo,proto3" json:"forward_to,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) Reset() {
|
||||||
|
*x = HtlcAccepted{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcAccepted) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HtlcAccepted.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HtlcAccepted) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) GetCorrelationid() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Correlationid
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) GetOnion() *Onion {
|
||||||
|
if x != nil {
|
||||||
|
return x.Onion
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) GetHtlc() *Htlc {
|
||||||
|
if x != nil {
|
||||||
|
return x.Htlc
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcAccepted) GetForwardTo() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ForwardTo
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Onion struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Payload string `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||||
|
ShortChannelId string `protobuf:"bytes,2,opt,name=short_channel_id,json=shortChannelId,proto3" json:"short_channel_id,omitempty"`
|
||||||
|
ForwardMsat uint64 `protobuf:"varint,3,opt,name=forward_msat,json=forwardMsat,proto3" json:"forward_msat,omitempty"`
|
||||||
|
OutgoingCltvValue uint32 `protobuf:"varint,4,opt,name=outgoing_cltv_value,json=outgoingCltvValue,proto3" json:"outgoing_cltv_value,omitempty"`
|
||||||
|
SharedSecret string `protobuf:"bytes,5,opt,name=shared_secret,json=sharedSecret,proto3" json:"shared_secret,omitempty"`
|
||||||
|
NextOnion string `protobuf:"bytes,6,opt,name=next_onion,json=nextOnion,proto3" json:"next_onion,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) Reset() {
|
||||||
|
*x = Onion{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Onion) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Onion) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Onion.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Onion) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetPayload() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Payload
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetShortChannelId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ShortChannelId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetForwardMsat() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ForwardMsat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetOutgoingCltvValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.OutgoingCltvValue
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetSharedSecret() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.SharedSecret
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Onion) GetNextOnion() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.NextOnion
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Htlc struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
ShortChannelId string `protobuf:"bytes,1,opt,name=short_channel_id,json=shortChannelId,proto3" json:"short_channel_id,omitempty"`
|
||||||
|
Id uint64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
AmountMsat uint64 `protobuf:"varint,3,opt,name=amount_msat,json=amountMsat,proto3" json:"amount_msat,omitempty"`
|
||||||
|
CltvExpiry uint32 `protobuf:"varint,4,opt,name=cltv_expiry,json=cltvExpiry,proto3" json:"cltv_expiry,omitempty"`
|
||||||
|
CltvExpiryRelative uint32 `protobuf:"varint,5,opt,name=cltv_expiry_relative,json=cltvExpiryRelative,proto3" json:"cltv_expiry_relative,omitempty"`
|
||||||
|
PaymentHash string `protobuf:"bytes,6,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) Reset() {
|
||||||
|
*x = Htlc{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Htlc) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Htlc) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Htlc.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Htlc) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetShortChannelId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ShortChannelId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetId() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetAmountMsat() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.AmountMsat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetCltvExpiry() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.CltvExpiry
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetCltvExpiryRelative() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.CltvExpiryRelative
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Htlc) GetPaymentHash() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.PaymentHash
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcResolution struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Correlationid string `protobuf:"bytes,1,opt,name=correlationid,proto3" json:"correlationid,omitempty"`
|
||||||
|
// Types that are assignable to Outcome:
|
||||||
|
// *HtlcResolution_Fail
|
||||||
|
// *HtlcResolution_Continue
|
||||||
|
// *HtlcResolution_Resolve
|
||||||
|
Outcome isHtlcResolution_Outcome `protobuf_oneof:"outcome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) Reset() {
|
||||||
|
*x = HtlcResolution{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcResolution) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HtlcResolution.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HtlcResolution) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) GetCorrelationid() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Correlationid
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HtlcResolution) GetOutcome() isHtlcResolution_Outcome {
|
||||||
|
if m != nil {
|
||||||
|
return m.Outcome
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) GetFail() *HtlcFail {
|
||||||
|
if x, ok := x.GetOutcome().(*HtlcResolution_Fail); ok {
|
||||||
|
return x.Fail
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) GetContinue() *HtlcContinue {
|
||||||
|
if x, ok := x.GetOutcome().(*HtlcResolution_Continue); ok {
|
||||||
|
return x.Continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolution) GetResolve() *HtlcResolve {
|
||||||
|
if x, ok := x.GetOutcome().(*HtlcResolution_Resolve); ok {
|
||||||
|
return x.Resolve
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type isHtlcResolution_Outcome interface {
|
||||||
|
isHtlcResolution_Outcome()
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcResolution_Fail struct {
|
||||||
|
Fail *HtlcFail `protobuf:"bytes,2,opt,name=fail,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcResolution_Continue struct {
|
||||||
|
Continue *HtlcContinue `protobuf:"bytes,3,opt,name=continue,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcResolution_Resolve struct {
|
||||||
|
Resolve *HtlcResolve `protobuf:"bytes,4,opt,name=resolve,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcResolution_Fail) isHtlcResolution_Outcome() {}
|
||||||
|
|
||||||
|
func (*HtlcResolution_Continue) isHtlcResolution_Outcome() {}
|
||||||
|
|
||||||
|
func (*HtlcResolution_Resolve) isHtlcResolution_Outcome() {}
|
||||||
|
|
||||||
|
type HtlcContinue struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Payload *string `protobuf:"bytes,1,opt,name=payload,proto3,oneof" json:"payload,omitempty"`
|
||||||
|
ForwardTo *string `protobuf:"bytes,2,opt,name=forward_to,json=forwardTo,proto3,oneof" json:"forward_to,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcContinue) Reset() {
|
||||||
|
*x = HtlcContinue{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcContinue) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcContinue) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HtlcContinue) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HtlcContinue.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HtlcContinue) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcContinue) GetPayload() string {
|
||||||
|
if x != nil && x.Payload != nil {
|
||||||
|
return *x.Payload
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcContinue) GetForwardTo() string {
|
||||||
|
if x != nil && x.ForwardTo != nil {
|
||||||
|
return *x.ForwardTo
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcFail struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Types that are assignable to Failure:
|
||||||
|
// *HtlcFail_FailureMessage
|
||||||
|
// *HtlcFail_FailureOnion
|
||||||
|
Failure isHtlcFail_Failure `protobuf_oneof:"failure"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcFail) Reset() {
|
||||||
|
*x = HtlcFail{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcFail) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcFail) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HtlcFail) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HtlcFail.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HtlcFail) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *HtlcFail) GetFailure() isHtlcFail_Failure {
|
||||||
|
if m != nil {
|
||||||
|
return m.Failure
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcFail) GetFailureMessage() string {
|
||||||
|
if x, ok := x.GetFailure().(*HtlcFail_FailureMessage); ok {
|
||||||
|
return x.FailureMessage
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcFail) GetFailureOnion() string {
|
||||||
|
if x, ok := x.GetFailure().(*HtlcFail_FailureOnion); ok {
|
||||||
|
return x.FailureOnion
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type isHtlcFail_Failure interface {
|
||||||
|
isHtlcFail_Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcFail_FailureMessage struct {
|
||||||
|
FailureMessage string `protobuf:"bytes,1,opt,name=failure_message,json=failureMessage,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HtlcFail_FailureOnion struct {
|
||||||
|
FailureOnion string `protobuf:"bytes,2,opt,name=failure_onion,json=failureOnion,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcFail_FailureMessage) isHtlcFail_Failure() {}
|
||||||
|
|
||||||
|
func (*HtlcFail_FailureOnion) isHtlcFail_Failure() {}
|
||||||
|
|
||||||
|
type HtlcResolve struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
PaymentKey string `protobuf:"bytes,1,opt,name=payment_key,json=paymentKey,proto3" json:"payment_key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolve) Reset() {
|
||||||
|
*x = HtlcResolve{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolve) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HtlcResolve) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HtlcResolve) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cln_plugin_proto_msgTypes[6]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HtlcResolve.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HtlcResolve) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cln_plugin_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HtlcResolve) GetPaymentKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.PaymentKey
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_cln_plugin_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_cln_plugin_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x10, 0x63, 0x6c, 0x6e, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x22, 0x8c, 0x01, 0x0a, 0x0c, 0x48, 0x74, 0x6c, 0x63, 0x41, 0x63, 0x63, 0x65, 0x70,
|
||||||
|
0x74, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72,
|
||||||
|
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x05, 0x6f, 0x6e, 0x69,
|
||||||
|
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x4f, 0x6e, 0x69, 0x6f, 0x6e,
|
||||||
|
0x52, 0x05, 0x6f, 0x6e, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x04, 0x68, 0x74, 0x6c, 0x63, 0x18,
|
||||||
|
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x04, 0x68, 0x74,
|
||||||
|
0x6c, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x6f,
|
||||||
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x54,
|
||||||
|
0x6f, 0x22, 0xe2, 0x01, 0x0a, 0x05, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70,
|
||||||
|
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61,
|
||||||
|
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x63,
|
||||||
|
0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x0e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12,
|
||||||
|
0x21, 0x0a, 0x0c, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18,
|
||||||
|
0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4d, 0x73,
|
||||||
|
0x61, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x63,
|
||||||
|
0x6c, 0x74, 0x76, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
|
0x11, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x74, 0x76, 0x56, 0x61, 0x6c,
|
||||||
|
0x75, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63,
|
||||||
|
0x72, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x65,
|
||||||
|
0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f,
|
||||||
|
0x6f, 0x6e, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78,
|
||||||
|
0x74, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x22, 0xd7, 0x01, 0x0a, 0x04, 0x48, 0x74, 0x6c, 0x63, 0x12,
|
||||||
|
0x28, 0x0a, 0x10, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
|
||||||
|
0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
||||||
|
0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||||
|
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6d, 0x6f,
|
||||||
|
0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
|
||||||
|
0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c,
|
||||||
|
0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
|
0x0a, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x63,
|
||||||
|
0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74,
|
||||||
|
0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6c, 0x74, 0x76, 0x45,
|
||||||
|
0x78, 0x70, 0x69, 0x72, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x21, 0x0a,
|
||||||
|
0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68,
|
||||||
|
0x22, 0xb9, 0x01, 0x0a, 0x0e, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74,
|
||||||
|
0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72,
|
||||||
|
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x04, 0x66, 0x61, 0x69,
|
||||||
|
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x46, 0x61,
|
||||||
|
0x69, 0x6c, 0x48, 0x00, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x12, 0x2b, 0x0a, 0x08, 0x63, 0x6f,
|
||||||
|
0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x48,
|
||||||
|
0x74, 0x6c, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63,
|
||||||
|
0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x6f, 0x6c,
|
||||||
|
0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x52,
|
||||||
|
0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76,
|
||||||
|
0x65, 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x22, 0x6c, 0x0a, 0x0c,
|
||||||
|
0x48, 0x74, 0x6c, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x07,
|
||||||
|
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
|
||||||
|
0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x66,
|
||||||
|
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||||
|
0x01, 0x52, 0x09, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x54, 0x6f, 0x88, 0x01, 0x01, 0x42,
|
||||||
|
0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f,
|
||||||
|
0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x6f, 0x22, 0x67, 0x0a, 0x08, 0x48, 0x74,
|
||||||
|
0x6c, 0x63, 0x46, 0x61, 0x69, 0x6c, 0x12, 0x29, 0x0a, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72,
|
||||||
|
0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||||
|
0x00, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||||
|
0x65, 0x12, 0x25, 0x0a, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x6e, 0x69,
|
||||||
|
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x66, 0x61, 0x69, 0x6c,
|
||||||
|
0x75, 0x72, 0x65, 0x4f, 0x6e, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c,
|
||||||
|
0x75, 0x72, 0x65, 0x22, 0x2e, 0x0a, 0x0b, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c,
|
||||||
|
0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65,
|
||||||
|
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
|
0x4b, 0x65, 0x79, 0x32, 0x3d, 0x0a, 0x09, 0x43, 0x6c, 0x6e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
|
||||||
|
0x12, 0x30, 0x0a, 0x0a, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0f,
|
||||||
|
0x2e, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x1a,
|
||||||
|
0x0d, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x28, 0x01,
|
||||||
|
0x30, 0x01, 0x42, 0x28, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x2f, 0x62, 0x72, 0x65, 0x65, 0x7a, 0x2f, 0x6c, 0x73, 0x70, 0x64, 0x2f, 0x63, 0x6c, 0x6e, 0x5f,
|
||||||
|
0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_cln_plugin_proto_rawDescOnce sync.Once
|
||||||
|
file_cln_plugin_proto_rawDescData = file_cln_plugin_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_cln_plugin_proto_rawDescGZIP() []byte {
|
||||||
|
file_cln_plugin_proto_rawDescOnce.Do(func() {
|
||||||
|
file_cln_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_cln_plugin_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_cln_plugin_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_cln_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||||
|
var file_cln_plugin_proto_goTypes = []interface{}{
|
||||||
|
(*HtlcAccepted)(nil), // 0: HtlcAccepted
|
||||||
|
(*Onion)(nil), // 1: Onion
|
||||||
|
(*Htlc)(nil), // 2: Htlc
|
||||||
|
(*HtlcResolution)(nil), // 3: HtlcResolution
|
||||||
|
(*HtlcContinue)(nil), // 4: HtlcContinue
|
||||||
|
(*HtlcFail)(nil), // 5: HtlcFail
|
||||||
|
(*HtlcResolve)(nil), // 6: HtlcResolve
|
||||||
|
}
|
||||||
|
var file_cln_plugin_proto_depIdxs = []int32{
|
||||||
|
1, // 0: HtlcAccepted.onion:type_name -> Onion
|
||||||
|
2, // 1: HtlcAccepted.htlc:type_name -> Htlc
|
||||||
|
5, // 2: HtlcResolution.fail:type_name -> HtlcFail
|
||||||
|
4, // 3: HtlcResolution.continue:type_name -> HtlcContinue
|
||||||
|
6, // 4: HtlcResolution.resolve:type_name -> HtlcResolve
|
||||||
|
3, // 5: ClnPlugin.HtlcStream:input_type -> HtlcResolution
|
||||||
|
0, // 6: ClnPlugin.HtlcStream:output_type -> HtlcAccepted
|
||||||
|
6, // [6:7] is the sub-list for method output_type
|
||||||
|
5, // [5:6] is the sub-list for method input_type
|
||||||
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
|
0, // [0:5] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_cln_plugin_proto_init() }
|
||||||
|
func file_cln_plugin_proto_init() {
|
||||||
|
if File_cln_plugin_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_cln_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HtlcAccepted); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Onion); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Htlc); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HtlcResolution); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HtlcContinue); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HtlcFail); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*HtlcResolve); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[3].OneofWrappers = []interface{}{
|
||||||
|
(*HtlcResolution_Fail)(nil),
|
||||||
|
(*HtlcResolution_Continue)(nil),
|
||||||
|
(*HtlcResolution_Resolve)(nil),
|
||||||
|
}
|
||||||
|
file_cln_plugin_proto_msgTypes[4].OneofWrappers = []interface{}{}
|
||||||
|
file_cln_plugin_proto_msgTypes[5].OneofWrappers = []interface{}{
|
||||||
|
(*HtlcFail_FailureMessage)(nil),
|
||||||
|
(*HtlcFail_FailureOnion)(nil),
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_cln_plugin_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 7,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_cln_plugin_proto_goTypes,
|
||||||
|
DependencyIndexes: file_cln_plugin_proto_depIdxs,
|
||||||
|
MessageInfos: file_cln_plugin_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_cln_plugin_proto = out.File
|
||||||
|
file_cln_plugin_proto_rawDesc = nil
|
||||||
|
file_cln_plugin_proto_goTypes = nil
|
||||||
|
file_cln_plugin_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -1,46 +1,56 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
option go_package="github.com/breez/lspd/cln_plugin";
|
option go_package="github.com/breez/lspd/cln_plugin/proto";
|
||||||
|
|
||||||
service ClnPlugin {
|
service ClnPlugin {
|
||||||
rpc HtlcStream(stream HtlcResolution) returns (stream HtlcAccepted);
|
rpc HtlcStream(stream HtlcResolution) returns (stream HtlcAccepted);
|
||||||
}
|
}
|
||||||
|
|
||||||
message HtlcAccepted {
|
message HtlcAccepted {
|
||||||
uint64 correlationid = 1;
|
string correlationid = 1;
|
||||||
Onion onion = 2;
|
Onion onion = 2;
|
||||||
HtlcOffer htlc = 3;
|
Htlc htlc = 3;
|
||||||
|
string forward_to = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Onion {
|
message Onion {
|
||||||
bytes payload = 1;
|
string payload = 1;
|
||||||
uint64 short_channel_id = 2;
|
string short_channel_id = 2;
|
||||||
uint64 forward_amount_msat = 3;
|
uint64 forward_msat = 3;
|
||||||
|
uint32 outgoing_cltv_value = 4;
|
||||||
|
string shared_secret = 5;
|
||||||
|
string next_onion = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HtlcOffer {
|
message Htlc {
|
||||||
uint64 amount_msat = 2;
|
string short_channel_id = 1;
|
||||||
uint32 cltv_expiry_relative = 3;
|
uint64 id = 2;
|
||||||
|
uint64 amount_msat = 3;
|
||||||
uint32 cltv_expiry = 4;
|
uint32 cltv_expiry = 4;
|
||||||
bytes payment_hash = 5;
|
uint32 cltv_expiry_relative = 5;
|
||||||
|
string payment_hash = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HtlcResolution {
|
message HtlcResolution {
|
||||||
uint64 correlationid = 1;
|
string correlationid = 1;
|
||||||
oneof outcome {
|
oneof outcome {
|
||||||
HtlcFail fail = 2;
|
HtlcFail fail = 2;
|
||||||
HtlcContinue continue = 3;
|
HtlcContinue continue = 3;
|
||||||
HtlcContinueWith continue_with = 4;
|
HtlcResolve resolve = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message HtlcFail {
|
|
||||||
bytes failure_message = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message HtlcContinue {
|
message HtlcContinue {
|
||||||
|
optional string payload = 1;
|
||||||
|
optional string forward_to = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HtlcContinueWith {
|
message HtlcFail {
|
||||||
bytes channel_id = 1;
|
oneof failure {
|
||||||
bytes payload = 2;
|
string failure_message = 1;
|
||||||
}
|
string failure_onion = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message HtlcResolve {
|
||||||
|
string payment_key = 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.2.0
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
// - protoc v3.21.8
|
// - protoc v3.21.12
|
||||||
// source: cln_plugin.proto
|
// source: cln_plugin.proto
|
||||||
|
|
||||||
package cln_plugin
|
package proto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
@@ -1 +0,0 @@
|
|||||||
LISTEN_ADDRESS=<address the lsp cln plugin listens on (ip:port)><address the lsp cln plugin listens on (ip:port)>
|
|
||||||
@@ -8,64 +8,103 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/breez/lspd/cln_plugin/proto"
|
||||||
grpc "google.golang.org/grpc"
|
grpc "google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var receiveWaitDelay = time.Millisecond * 200
|
// A subscription represents a grpc client that is connected to the server.
|
||||||
|
|
||||||
type subscription struct {
|
type subscription struct {
|
||||||
stream ClnPlugin_HtlcStreamServer
|
stream proto.ClnPlugin_HtlcStreamServer
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
}
|
err chan error
|
||||||
type server struct {
|
|
||||||
ClnPluginServer
|
|
||||||
listenAddress string
|
|
||||||
grpcServer *grpc.Server
|
|
||||||
startMtx sync.Mutex
|
|
||||||
corrMtx sync.Mutex
|
|
||||||
subscription *subscription
|
|
||||||
newSubscriber chan struct{}
|
|
||||||
done chan struct{}
|
|
||||||
correlations map[uint64]chan *HtlcResolution
|
|
||||||
index uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(listenAddress string) *server {
|
// Internal htlc_accepted message meant for the sendQueue.
|
||||||
|
type htlcAcceptedMsg struct {
|
||||||
|
id string
|
||||||
|
htlc *HtlcAccepted
|
||||||
|
timeout <-chan time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal htlc result message meant for the recvQueue.
|
||||||
|
type htlcResultMsg struct {
|
||||||
|
id string
|
||||||
|
result interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
proto.ClnPluginServer
|
||||||
|
listenAddress string
|
||||||
|
subscriberTimeout time.Duration
|
||||||
|
grpcServer *grpc.Server
|
||||||
|
mtx sync.Mutex
|
||||||
|
subscription *subscription
|
||||||
|
newSubscriber chan struct{}
|
||||||
|
started chan struct{}
|
||||||
|
startError chan error
|
||||||
|
done chan struct{}
|
||||||
|
sendQueue chan *htlcAcceptedMsg
|
||||||
|
recvQueue chan *htlcResultMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new grpc server
|
||||||
|
func NewServer(listenAddress string, subscriberTimeout time.Duration) *server {
|
||||||
|
// TODO: Set a sane max queue size
|
||||||
return &server{
|
return &server{
|
||||||
listenAddress: listenAddress,
|
listenAddress: listenAddress,
|
||||||
newSubscriber: make(chan struct{}, 1),
|
subscriberTimeout: subscriberTimeout,
|
||||||
correlations: make(map[uint64]chan *HtlcResolution),
|
sendQueue: make(chan *htlcAcceptedMsg, 10000),
|
||||||
index: 0,
|
recvQueue: make(chan *htlcResultMsg, 10000),
|
||||||
|
started: make(chan struct{}),
|
||||||
|
startError: make(chan error, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starts the grpc server. Blocks until the servver is stopped. WaitStarted can
|
||||||
|
// be called to ensure the server is started without errors if this function
|
||||||
|
// is run as a goroutine.
|
||||||
func (s *server) Start() error {
|
func (s *server) Start() error {
|
||||||
s.startMtx.Lock()
|
s.mtx.Lock()
|
||||||
if s.grpcServer != nil {
|
if s.grpcServer != nil {
|
||||||
s.startMtx.Unlock()
|
s.mtx.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", s.listenAddress)
|
lis, err := net.Listen("tcp", s.listenAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ERROR Server failed to listen: %v", err)
|
log.Printf("ERROR Server failed to listen: %v", err)
|
||||||
s.startMtx.Unlock()
|
s.startError <- err
|
||||||
|
s.mtx.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.done = make(chan struct{})
|
s.done = make(chan struct{})
|
||||||
|
s.newSubscriber = make(chan struct{})
|
||||||
s.grpcServer = grpc.NewServer()
|
s.grpcServer = grpc.NewServer()
|
||||||
s.startMtx.Unlock()
|
s.mtx.Unlock()
|
||||||
RegisterClnPluginServer(s.grpcServer, s)
|
proto.RegisterClnPluginServer(s.grpcServer, s)
|
||||||
|
|
||||||
log.Printf("Server starting to listen on %s.", s.listenAddress)
|
log.Printf("Server starting to listen on %s.", s.listenAddress)
|
||||||
|
go s.listenHtlcRequests()
|
||||||
go s.listenHtlcResponses()
|
go s.listenHtlcResponses()
|
||||||
|
close(s.started)
|
||||||
return s.grpcServer.Serve(lis)
|
return s.grpcServer.Serve(lis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Waits until the server has started, or errored during startup.
|
||||||
|
func (s *server) WaitStarted() error {
|
||||||
|
select {
|
||||||
|
case <-s.started:
|
||||||
|
return nil
|
||||||
|
case err := <-s.startError:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops all work from the grpc server immediately.
|
||||||
func (s *server) Stop() {
|
func (s *server) Stop() {
|
||||||
s.startMtx.Lock()
|
s.mtx.Lock()
|
||||||
defer s.startMtx.Unlock()
|
defer s.mtx.Unlock()
|
||||||
log.Printf("Server Stop() called.")
|
log.Printf("Server Stop() called.")
|
||||||
if s.grpcServer == nil {
|
if s.grpcServer == nil {
|
||||||
return
|
return
|
||||||
@@ -76,36 +115,38 @@ func (s *server) Stop() {
|
|||||||
s.grpcServer = nil
|
s.grpcServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) HtlcStream(stream ClnPlugin_HtlcStreamServer) error {
|
// Grpc method that is called when a new client subscribes. There can only be
|
||||||
|
// one subscriber active at a time. If there is an error receiving or sending
|
||||||
|
// from or to the subscriber, the subscription is closed.
|
||||||
|
func (s *server) HtlcStream(stream proto.ClnPlugin_HtlcStreamServer) error {
|
||||||
log.Printf("Got HTLC stream subscription request.")
|
log.Printf("Got HTLC stream subscription request.")
|
||||||
s.startMtx.Lock()
|
s.mtx.Lock()
|
||||||
if s.subscription != nil {
|
if s.subscription != nil {
|
||||||
s.startMtx.Unlock()
|
s.mtx.Unlock()
|
||||||
return fmt.Errorf("already subscribed")
|
return fmt.Errorf("already subscribed")
|
||||||
}
|
}
|
||||||
|
|
||||||
sb := &subscription{
|
sb := &subscription{
|
||||||
stream: stream,
|
stream: stream,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
|
err: make(chan error, 1),
|
||||||
}
|
}
|
||||||
s.subscription = sb
|
s.subscription = sb
|
||||||
s.newSubscriber <- struct{}{}
|
|
||||||
s.startMtx.Unlock()
|
// Notify listeners that a new subscriber is active. Replace the chan with
|
||||||
|
// a new one immediately in case this subscriber is dropped later.
|
||||||
|
close(s.newSubscriber)
|
||||||
|
s.newSubscriber = make(chan struct{})
|
||||||
|
s.mtx.Unlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
s.startMtx.Lock()
|
s.removeSubscriptionIfUnchanged(sb, nil)
|
||||||
s.subscription = nil
|
|
||||||
close(sb.done)
|
|
||||||
s.startMtx.Unlock()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-stream.Context().Done()
|
<-stream.Context().Done()
|
||||||
log.Printf("HtlcStream context is done. Removing subscriber: %v", stream.Context().Err())
|
log.Printf("HtlcStream context is done. Removing subscriber: %v", stream.Context().Err())
|
||||||
s.startMtx.Lock()
|
s.removeSubscriptionIfUnchanged(sb, stream.Context().Err())
|
||||||
s.subscription = nil
|
|
||||||
close(sb.done)
|
|
||||||
s.startMtx.Unlock()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -115,82 +156,179 @@ func (s *server) HtlcStream(stream ClnPlugin_HtlcStreamServer) error {
|
|||||||
case <-sb.done:
|
case <-sb.done:
|
||||||
log.Printf("HTLC stream signalled done. Return EOF.")
|
log.Printf("HTLC stream signalled done. Return EOF.")
|
||||||
return io.EOF
|
return io.EOF
|
||||||
|
case err := <-sb.err:
|
||||||
|
log.Printf("HTLC stream signalled error. Return %v", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Send(h *HtlcAccepted) *HtlcResolution {
|
// Enqueues a htlc_accepted message for send to the grpc client.
|
||||||
sb := s.subscription
|
func (s *server) Send(id string, h *HtlcAccepted) {
|
||||||
if sb == nil {
|
s.sendQueue <- &htlcAcceptedMsg{
|
||||||
log.Printf("No subscribers available. Ignoring HtlcAccepted %+v", h)
|
id: id,
|
||||||
return s.defaultResolution()
|
htlc: h,
|
||||||
}
|
timeout: time.After(s.subscriberTimeout),
|
||||||
|
|
||||||
c := make(chan *HtlcResolution)
|
|
||||||
s.corrMtx.Lock()
|
|
||||||
s.index++
|
|
||||||
index := s.index
|
|
||||||
s.correlations[index] = c
|
|
||||||
s.corrMtx.Unlock()
|
|
||||||
|
|
||||||
h.Correlationid = index
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
s.corrMtx.Lock()
|
|
||||||
delete(s.correlations, index)
|
|
||||||
s.corrMtx.Unlock()
|
|
||||||
close(c)
|
|
||||||
}()
|
|
||||||
|
|
||||||
log.Printf("Sending HtlcAccepted: %+v", h)
|
|
||||||
err := sb.stream.Send(h)
|
|
||||||
if err != nil {
|
|
||||||
// TODO: Close the connection? Reset the subscriber?
|
|
||||||
log.Printf("Send() errored, Correlationid: %d: %v", index, err)
|
|
||||||
return s.defaultResolution()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receives the next htlc resolution message from the grpc client. Returns id
|
||||||
|
// and message. Blocks until a message is available. Returns a nil message if
|
||||||
|
// the server is done.
|
||||||
|
func (s *server) Receive() (string, interface{}) {
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
log.Printf("Signalled done while waiting for htlc resolution, Correlationid: %d, Ignoring: %+v", index, h)
|
return "", nil
|
||||||
return s.defaultResolution()
|
case msg := <-s.recvQueue:
|
||||||
case resolution := <-c:
|
return msg.id, msg.result
|
||||||
log.Printf("Got resolution, Correlationid: %d: %+v", index, h)
|
|
||||||
return resolution
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) recv() *HtlcResolution {
|
// Helper function that blocks until a message from a grpc client is received
|
||||||
|
// or the server stops. Either returns a received message, or nil if the server
|
||||||
|
// has stopped.
|
||||||
|
func (s *server) recv() *proto.HtlcResolution {
|
||||||
for {
|
for {
|
||||||
|
// make a copy of the used fields, to make sure state updates don't
|
||||||
|
// surprise us. The newSubscriber chan is swapped whenever a new
|
||||||
|
// subscriber arrives.
|
||||||
|
s.mtx.Lock()
|
||||||
sb := s.subscription
|
sb := s.subscription
|
||||||
|
ns := s.newSubscriber
|
||||||
|
s.mtx.Unlock()
|
||||||
|
|
||||||
if sb == nil {
|
if sb == nil {
|
||||||
log.Printf("Got no subscribers for receive. Waiting for subscriber.")
|
log.Printf("Got no subscribers for receive. Waiting for subscriber.")
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
log.Printf("Done signalled, stopping receive.")
|
log.Printf("Done signalled, stopping receive.")
|
||||||
return s.defaultResolution()
|
return nil
|
||||||
case <-s.newSubscriber:
|
case <-ns:
|
||||||
log.Printf("New subscription available for receive, continue receive.")
|
log.Printf("New subscription available for receive, continue receive.")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is a subscription active. Attempt to receive a message.
|
||||||
r, err := sb.stream.Recv()
|
r, err := sb.stream.Recv()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Printf("Received HtlcResolution %+v", r)
|
log.Printf("Received HtlcResolution %+v", r)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: close the subscription??
|
// Receiving the message failed, so the subscription is broken. Remove
|
||||||
log.Printf("Recv() errored, waiting %v: %v", receiveWaitDelay, err)
|
// it if it hasn't been updated already. We'll try receiving again in
|
||||||
|
// the next iteration of the for loop.
|
||||||
|
log.Printf("Recv() errored, removing subscription: %v", err)
|
||||||
|
s.removeSubscriptionIfUnchanged(sb, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops and removes the subscription if this is the currently active
|
||||||
|
// subscription. If the subscription was changed in the meantime, this function
|
||||||
|
// does nothing.
|
||||||
|
func (s *server) removeSubscriptionIfUnchanged(sb *subscription, err error) {
|
||||||
|
s.mtx.Lock()
|
||||||
|
// If the subscription reference hasn't changed yet in the meantime, kill it.
|
||||||
|
if s.subscription == sb {
|
||||||
|
if err == nil {
|
||||||
|
close(sb.done)
|
||||||
|
} else {
|
||||||
|
sb.err <- err
|
||||||
|
}
|
||||||
|
s.subscription = nil
|
||||||
|
}
|
||||||
|
s.mtx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listens to sendQueue for htlc_accepted requests from cln. The message will be
|
||||||
|
// held until a subscriber is active, or the subscriber timeout expires. The
|
||||||
|
// messages are sent to the grpc client in fifo order.
|
||||||
|
func (s *server) listenHtlcRequests() {
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
log.Printf("Done signalled, stopping receive.")
|
log.Printf("listenHtlcRequests received done. Stop listening.")
|
||||||
return s.defaultResolution()
|
return
|
||||||
case <-time.After(receiveWaitDelay):
|
case msg := <-s.sendQueue:
|
||||||
|
s.handleHtlcAccepted(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempts to send a htlc_accepted message to the grpc client. The message will
|
||||||
|
// be held until a subscriber is active, or the subscriber timeout expires.
|
||||||
|
func (s *server) handleHtlcAccepted(msg *htlcAcceptedMsg) {
|
||||||
|
for {
|
||||||
|
s.mtx.Lock()
|
||||||
|
sb := s.subscription
|
||||||
|
ns := s.newSubscriber
|
||||||
|
s.mtx.Unlock()
|
||||||
|
|
||||||
|
// If there is no active subscription, wait until there is a new
|
||||||
|
// subscriber, or the message times out.
|
||||||
|
if sb == nil {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
log.Printf("handleHtlcAccepted received server done. Stop processing.")
|
||||||
|
return
|
||||||
|
case <-ns:
|
||||||
|
log.Printf("got a new subscriber. continue handleHtlcAccepted.")
|
||||||
|
continue
|
||||||
|
case <-msg.timeout:
|
||||||
|
log.Printf(
|
||||||
|
"WARNING: htlc with id '%s' timed out after '%v' waiting "+
|
||||||
|
"for grpc subscriber: %+v",
|
||||||
|
msg.id,
|
||||||
|
s.subscriberTimeout,
|
||||||
|
msg.htlc,
|
||||||
|
)
|
||||||
|
s.recvQueue <- &htlcResultMsg{
|
||||||
|
id: msg.id,
|
||||||
|
result: s.defaultResult(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is a subscriber. Attempt to send the htlc_accepted message.
|
||||||
|
err := sb.stream.Send(&proto.HtlcAccepted{
|
||||||
|
Correlationid: msg.id,
|
||||||
|
Onion: &proto.Onion{
|
||||||
|
Payload: msg.htlc.Onion.Payload,
|
||||||
|
ShortChannelId: msg.htlc.Onion.ShortChannelId,
|
||||||
|
ForwardMsat: msg.htlc.Onion.ForwardMsat,
|
||||||
|
OutgoingCltvValue: msg.htlc.Onion.OutgoingCltvValue,
|
||||||
|
SharedSecret: msg.htlc.Onion.SharedSecret,
|
||||||
|
NextOnion: msg.htlc.Onion.NextOnion,
|
||||||
|
},
|
||||||
|
Htlc: &proto.Htlc{
|
||||||
|
ShortChannelId: msg.htlc.Htlc.ShortChannelId,
|
||||||
|
Id: msg.htlc.Htlc.Id,
|
||||||
|
AmountMsat: msg.htlc.Htlc.AmountMsat,
|
||||||
|
CltvExpiry: msg.htlc.Htlc.CltvExpiry,
|
||||||
|
CltvExpiryRelative: msg.htlc.Htlc.CltvExpiryRelative,
|
||||||
|
PaymentHash: msg.htlc.Htlc.PaymentHash,
|
||||||
|
},
|
||||||
|
ForwardTo: msg.htlc.ForwardTo,
|
||||||
|
})
|
||||||
|
|
||||||
|
// If there is no error, we're done.
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we end up here, there was an error sending the message to the
|
||||||
|
// grpc client.
|
||||||
|
log.Printf("Error sending htlc_accepted message to subscriber. "+
|
||||||
|
"Removing subscription: %v", err)
|
||||||
|
s.removeSubscriptionIfUnchanged(sb, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listens to htlc responses from the grpc client and appends them to the
|
||||||
|
// receive queue. The messages from the receive queue are read in the Receive
|
||||||
|
// function.
|
||||||
func (s *server) listenHtlcResponses() {
|
func (s *server) listenHtlcResponses() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -198,23 +336,77 @@ func (s *server) listenHtlcResponses() {
|
|||||||
log.Printf("listenHtlcResponses received done. Stopping listening.")
|
log.Printf("listenHtlcResponses received done. Stopping listening.")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
response := s.recv()
|
resp := s.recv()
|
||||||
s.corrMtx.Lock()
|
s.recvQueue <- &htlcResultMsg{
|
||||||
correlation, ok := s.correlations[response.Correlationid]
|
id: resp.Correlationid,
|
||||||
s.corrMtx.Unlock()
|
result: s.mapResult(resp.Outcome),
|
||||||
if ok {
|
|
||||||
correlation <- response
|
|
||||||
} else {
|
|
||||||
log.Printf("Got HTLC resolution that could not be correlated: %+v", response)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) defaultResolution() *HtlcResolution {
|
// Maps a grpc result to the corresponding result for cln. The cln message
|
||||||
return &HtlcResolution{
|
// is a raw json message, so it's easiest to use a map directly.
|
||||||
Outcome: &HtlcResolution_Continue{
|
func (s *server) mapResult(outcome interface{}) interface{} {
|
||||||
Continue: &HtlcContinue{},
|
// result: continue
|
||||||
},
|
cont, ok := outcome.(*proto.HtlcResolution_Continue)
|
||||||
|
if ok {
|
||||||
|
result := map[string]interface{}{
|
||||||
|
"result": "continue",
|
||||||
|
}
|
||||||
|
|
||||||
|
if cont.Continue.ForwardTo != nil {
|
||||||
|
result["forward_to"] = *cont.Continue.ForwardTo
|
||||||
|
}
|
||||||
|
|
||||||
|
if cont.Continue.Payload != nil {
|
||||||
|
result["payload"] = *cont.Continue.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// result: fail
|
||||||
|
fail, ok := outcome.(*proto.HtlcResolution_Fail)
|
||||||
|
if ok {
|
||||||
|
result := map[string]interface{}{
|
||||||
|
"result": "fail",
|
||||||
|
}
|
||||||
|
|
||||||
|
fm, ok := fail.Fail.Failure.(*proto.HtlcFail_FailureMessage)
|
||||||
|
if ok {
|
||||||
|
result["failure_message"] = fm.FailureMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
fo, ok := fail.Fail.Failure.(*proto.HtlcFail_FailureOnion)
|
||||||
|
if ok {
|
||||||
|
result["failure_onion"] = fo.FailureOnion
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// result: resolve
|
||||||
|
resolve, ok := outcome.(*proto.HtlcResolution_Resolve)
|
||||||
|
if ok {
|
||||||
|
result := map[string]interface{}{
|
||||||
|
"result": "resolve",
|
||||||
|
"payment_key": resolve.Resolve.PaymentKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// On an unknown result we haven't implemented all possible cases from the
|
||||||
|
// grpc message. We don't understand what's going on, so we'll return
|
||||||
|
// result: continue.
|
||||||
|
log.Printf("Unexpected htlc resolution type %T: %+v", outcome, outcome)
|
||||||
|
return s.defaultResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a result: continue message.
|
||||||
|
func (s *server) defaultResult() interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"result": "continue",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ type ClnLspNode struct {
|
|||||||
isInitialized bool
|
isInitialized bool
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
pluginBinary string
|
pluginBinary string
|
||||||
pluginFile string
|
|
||||||
pluginAddress string
|
pluginAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +42,6 @@ type clnLspNodeRuntime struct {
|
|||||||
|
|
||||||
func NewClnLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string) LspNode {
|
func NewClnLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string) LspNode {
|
||||||
scriptDir := h.GetDirectory("lspd")
|
scriptDir := h.GetDirectory("lspd")
|
||||||
pluginFile := filepath.Join(scriptDir, "htlc.sh")
|
|
||||||
pluginBinary := *clnPluginExec
|
pluginBinary := *clnPluginExec
|
||||||
pluginPort, err := lntest.GetPort()
|
pluginPort, err := lntest.GetPort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -52,7 +50,8 @@ func NewClnLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string) LspNode
|
|||||||
pluginAddress := fmt.Sprintf("127.0.0.1:%d", pluginPort)
|
pluginAddress := fmt.Sprintf("127.0.0.1:%d", pluginPort)
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
fmt.Sprintf("--plugin=%s", pluginFile),
|
fmt.Sprintf("--plugin=%s", pluginBinary),
|
||||||
|
fmt.Sprintf("--lsp.listen=%s", pluginAddress),
|
||||||
fmt.Sprintf("--fee-base=%d", lspBaseFeeMsat),
|
fmt.Sprintf("--fee-base=%d", lspBaseFeeMsat),
|
||||||
fmt.Sprintf("--fee-per-satoshi=%d", lspFeeRatePpm),
|
fmt.Sprintf("--fee-per-satoshi=%d", lspFeeRatePpm),
|
||||||
fmt.Sprintf("--cltv-delta=%d", lspCltvDelta),
|
fmt.Sprintf("--cltv-delta=%d", lspCltvDelta),
|
||||||
@@ -79,7 +78,6 @@ func NewClnLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string) LspNode
|
|||||||
logFilePath: logFilePath,
|
logFilePath: logFilePath,
|
||||||
lspBase: lspbase,
|
lspBase: lspbase,
|
||||||
pluginBinary: pluginBinary,
|
pluginBinary: pluginBinary,
|
||||||
pluginFile: pluginFile,
|
|
||||||
pluginAddress: pluginAddress,
|
pluginAddress: pluginAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,16 +100,6 @@ func (c *ClnLspNode) Start() {
|
|||||||
Name: fmt.Sprintf("%s: lsp base", c.lspBase.name),
|
Name: fmt.Sprintf("%s: lsp base", c.lspBase.name),
|
||||||
Fn: c.lspBase.Stop,
|
Fn: c.lspBase.Stop,
|
||||||
})
|
})
|
||||||
|
|
||||||
pluginContent := fmt.Sprintf(`#!/bin/bash
|
|
||||||
export LISTEN_ADDRESS=%s
|
|
||||||
%s`, c.pluginAddress, c.pluginBinary)
|
|
||||||
|
|
||||||
err = os.WriteFile(c.pluginFile, []byte(pluginContent), 0755)
|
|
||||||
if err != nil {
|
|
||||||
lntest.PerformCleanup(cleanups)
|
|
||||||
c.harness.T.Fatalf("failed create lsp cln plugin file: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.lightningNode.Start()
|
c.lightningNode.Start()
|
||||||
|
|||||||
Reference in New Issue
Block a user