Add cln channel acceptor

This commit is contained in:
Yaacov Akiba Slama
2023-07-01 22:39:07 +03:00
parent 34646d50a5
commit 70d6afcf85
3 changed files with 176 additions and 10 deletions

View File

@@ -19,6 +19,7 @@ import (
const (
SubscriberTimeoutOption = "lsp-subscribertimeout"
ListenAddressOption = "lsp-listen"
channelAcceptScript = "lsp-channel-accept-script"
)
var (
@@ -43,11 +44,12 @@ var (
)
type ClnPlugin struct {
done chan struct{}
server *server
in *os.File
out *bufio.Writer
writeMtx sync.Mutex
done chan struct{}
server *server
in *os.File
out *bufio.Writer
writeMtx sync.Mutex
channelAcceptScript string
}
func NewClnPlugin(in, out *os.File) *ClnPlugin {
@@ -210,6 +212,20 @@ func (c *ClnPlugin) processRequest(request *Request) {
c.handleShutdown(request)
case "htlc_accepted":
c.handleHtlcAccepted(request)
case "openchannel":
// handle open channel in a goroutine, because order doesn't matter.
go c.handleOpenChannel(request)
case "openchannel2":
// handle open channel in a goroutine, because order doesn't matter.
go c.handleOpenChannel(request)
case "getchannelacceptscript":
c.sendToCln(&Response{
JsonRpc: SpecVersion,
Id: request.Id,
Result: c.channelAcceptScript,
})
case "setchannelacceptscript":
c.handleSetChannelAcceptScript(request)
default:
c.sendError(
request.Id,
@@ -239,14 +255,28 @@ func (c *ClnPlugin) handleGetManifest(request *Request) {
"if no subscriber is active. golang duration string.",
Default: &DefaultSubscriberTimeout,
},
},
RpcMethods: []*RpcMethod{},
Dynamic: true,
Hooks: []Hook{
{
Name: "htlc_accepted",
Name: channelAcceptScript,
Type: "string",
Description: "starlark script for channel acceptor.",
},
},
RpcMethods: []*RpcMethod{
{
Name: "getchannelacceptscript",
Description: "Get the startlark channel acceptor script",
},
{
Name: "setchannelacceptscript",
Description: "Set the startlark channel acceptor script",
},
},
Dynamic: true,
Hooks: []Hook{
{Name: "htlc_accepted"},
{Name: "openchannel"},
{Name: "openchannel2"},
},
NonNumericIds: true,
Subscriptions: []string{
"shutdown",
@@ -270,6 +300,31 @@ func (c *ClnPlugin) handleInit(request *Request) {
return
}
// Get the channel acceptor script option.
sc, ok := initMsg.Options[channelAcceptScript]
if !ok {
c.sendError(
request.Id,
InvalidParams,
fmt.Sprintf("Missing option '%s'", channelAcceptScript),
)
return
}
c.channelAcceptScript, ok = sc.(string)
if !ok {
c.sendError(
request.Id,
InvalidParams,
fmt.Sprintf(
"Invalid value '%v' for option '%s'",
sc,
channelAcceptScript,
),
)
return
}
// Get the listen address option.
l, ok := initMsg.Options[ListenAddressOption]
if !ok {
@@ -382,6 +437,79 @@ func (c *ClnPlugin) handleHtlcAccepted(request *Request) {
c.server.Send(idToString(request.Id), &htlc)
}
func (c *ClnPlugin) handleSetChannelAcceptScript(request *Request) {
var params []string
err := json.Unmarshal(request.Params, &params)
if err != nil {
c.sendError(
request.Id,
ParseError,
fmt.Sprintf(
"Failed to unmarshal setchannelacceptscript params:%s [%s]",
err.Error(),
request.Params,
),
)
return
}
if len(params) >= 1 {
c.channelAcceptScript = params[0]
}
c.sendToCln(&Response{
JsonRpc: SpecVersion,
Id: request.Id,
Result: c.channelAcceptScript,
})
}
func unmarshalOpenChannel(request *Request) (r json.RawMessage, err error) {
switch request.Method {
case "openchannel":
var openChannel struct {
OpenChannel json.RawMessage `json:"openchannel"`
}
err = json.Unmarshal(request.Params, &openChannel)
if err != nil {
return
}
r = openChannel.OpenChannel
case "openchannel2":
var openChannel struct {
OpenChannel json.RawMessage `json:"openchannel2"`
}
err = json.Unmarshal(request.Params, &openChannel)
if err != nil {
return
}
r = openChannel.OpenChannel
}
return r, nil
}
func (c *ClnPlugin) handleOpenChannel(request *Request) {
p, err := unmarshalOpenChannel(request)
if err != nil {
c.sendError(
request.Id,
ParseError,
fmt.Sprintf(
"Failed to unmarshal openchannel params:%s [%s]",
err.Error(),
request.Params,
),
)
return
}
result, err := channelAcceptor(c.channelAcceptScript, request.Method, p)
if err != nil {
log.Printf("channelAcceptor error - request: %s error: %v", request, err)
}
c.sendToCln(&Response{
JsonRpc: SpecVersion,
Id: request.Id,
Result: result,
})
}
// Sends an error to cln.
func (c *ClnPlugin) sendError(id json.RawMessage, code int, message string) {
// Log the error to cln first.