Skip to content

Commit

Permalink
clightning: config parsing deprecated plugins
Browse files Browse the repository at this point in the history
- Refactor the BitcoinFallbackFromClnConfig function to use the new
  `configs` structure instead of `important-plugins`.
- https://docs.corelightning.org/reference/lightning-listconfigs
  • Loading branch information
YusukeShimizu committed Dec 18, 2024
1 parent ecf1b6e commit 644de2e
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 67 deletions.
177 changes: 114 additions & 63 deletions clightning/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,85 +334,136 @@ func SetBitcoinNetwork(client *ClightningClient) Processor {
}
}

// Structs for parsed CLN configs
// ParsedClnConfig represents the configuration for cln (Core Lightning).
// It includes fields for versions before and after v24.11.
// For versions before v24.11, ImportantPlugins holds plugin configurations.
// For versions v24.11 and later, Configs contains detailed config settings.
type ParsedClnConfig struct {
ImportantPlugins []*PluginConfig `json:"important-plugins"`
Configs map[string]ConfigEntry `json:"configs"`
}

type PluginConfig struct {
Path string `json:"path"`
Name string `json:"name"`
Options map[string]interface{} `json:"options"`
}

type ConfigEntry struct {
ValueStr string `json:"value_str"`
ValueInt int `json:"value_int"`
}

// BitcoinFallbackFromClnConfig
// if no bitcoin config is set at all, try to fall back to cln bitcoin config.
// If no bitcoin config is set at all, try to fall back to CLN bitcoin config.
func BitcoinFallbackFromClnConfig(client *ClightningClient) Processor {
return func(c *Config) (*Config, error) {
if c.Bitcoin.RpcUser == "" && c.Bitcoin.RpcPassword == "" &&
c.Bitcoin.RpcPasswordFile == "" && c.Bitcoin.RpcHost == "" &&
c.Bitcoin.RpcPort == 0 {
// No bitcoin config is set, we try to fetch it from CLN.
if isBitcoinConfigEmpty(c.Bitcoin) {
conf, err := client.glightning.ListConfigs()
if err != nil {
return nil, err
}

// Parse interface data into struct.
data, err := json.Marshal(conf)
parsedConfig, err := parseClnConfig(conf)
if err != nil {
return nil, err
}
updateBitcoinConfig(c, parsedConfig)
}
return c, nil
}
}

var listConfigResponse struct {
ImportantPlugins []*struct {
Path string
Name string
Options map[string]interface{}
} `json:"important-plugins"`
}
err = json.Unmarshal(data, &listConfigResponse)
if err != nil {
return nil, err
}
func isBitcoinConfigEmpty(bitcoin *BitcoinConf) bool {
return bitcoin.RpcUser == "" && bitcoin.RpcPassword == "" &&
bitcoin.RpcPasswordFile == "" && bitcoin.RpcHost == "" && bitcoin.RpcPort == 0
}

// Extract settings from the `bcli` plugin.
for _, plugin := range listConfigResponse.ImportantPlugins {
if plugin.Name == "bcli" {
// Extract the bitcoind config
if v, ok := plugin.Options["bitcoin-datadir"]; ok {
if v != nil {
c.Bitcoin.DataDir = v.(string)
}
}
if v, ok := plugin.Options["bitcoin-rpcuser"]; ok {
if v != nil {
c.Bitcoin.RpcUser = v.(string)
}
}
if v, ok := plugin.Options["bitcoin-rpcpassword"]; ok {
if v != nil {
c.Bitcoin.RpcPassword = v.(string)
}
}
if v, ok := plugin.Options["bitcoin-rpcconnect"]; ok {
if v != nil {
c.Bitcoin.RpcHost = v.(string)
}
}
if v, ok := plugin.Options["bitcoin-rpcport"]; ok {
if v != nil {
// detect if type is string (CLN < v23.08)
switch p := v.(type) {
case string:
port, err := strconv.Atoi(p)
if err != nil {
return nil, err
}
c.Bitcoin.RpcPort = uint(port)
case float64:
c.Bitcoin.RpcPort = uint(p)
default:
return nil, fmt.Errorf("Bitcoind rpcport type %T not handled", v)
}
}
}
}
}
func parseClnConfig(conf interface{}) (*ParsedClnConfig, error) {
data, err := json.Marshal(conf)
if err != nil {
return nil, err
}

var parsedConfig ParsedClnConfig
if err := json.Unmarshal(data, &parsedConfig); err != nil {
return nil, err
}

return &parsedConfig, nil
}

func updateBitcoinConfig(c *Config, parsedConfig *ParsedClnConfig) {
if parsedConfig.Configs != nil {
applyConfigMap(c, parsedConfig.Configs)
}
applyPluginConfig(c, parsedConfig.ImportantPlugins)
}

func applyConfigMap(c *Config, configs map[string]ConfigEntry) {
if v, ok := configs["bitcoin-datadir"]; ok {
c.Bitcoin.DataDir = v.ValueStr
}
if v, ok := configs["bitcoin-rpcuser"]; ok {
c.Bitcoin.RpcUser = v.ValueStr
}
if v, ok := configs["bitcoin-rpcpassword"]; ok {
c.Bitcoin.RpcPassword = v.ValueStr
}
if v, ok := configs["bitcoin-rpcconnect"]; ok {
c.Bitcoin.RpcHost = v.ValueStr
}
if v, ok := configs["bitcoin-rpcport"]; ok {
c.Bitcoin.RpcPort = uint(v.ValueInt)
}
}

func applyPluginConfig(c *Config, plugins []*PluginConfig) {
for _, plugin := range plugins {
if plugin.Name == "bcli" {
applyBcliOptions(c, plugin.Options)
}
return c, nil
}
}

func applyBcliOptions(c *Config, options map[string]interface{}) {
if v, ok := options["bitcoin-datadir"]; ok {
c.Bitcoin.DataDir = toString(v)
}
if v, ok := options["bitcoin-rpcuser"]; ok {
c.Bitcoin.RpcUser = toString(v)
}
if v, ok := options["bitcoin-rpcpassword"]; ok {
c.Bitcoin.RpcPassword = toString(v)
}
if v, ok := options["bitcoin-rpcconnect"]; ok {
c.Bitcoin.RpcHost = toString(v)
}
if v, ok := options["bitcoin-rpcport"]; ok {
c.Bitcoin.RpcPort = toUint(v)
}
}

func toString(v interface{}) string {
if str, ok := v.(string); ok {
return str
}
return ""
}

func toUint(v interface{}) uint {
switch val := v.(type) {
case string:
port, err := strconv.Atoi(val)
if err == nil {
return uint(port)
}
case float64:
return uint(val)
}
return 0
}

// BitcoinFallback sets default values for empty config options.
func BitcoinFallback() Processor {
return func(c *Config) (*Config, error) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ require (
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.1.0
golang.org/x/term v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
20 changes: 17 additions & 3 deletions test/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/elementsproject/peerswap/testframework"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"
)

const (
Expand Down Expand Up @@ -102,9 +103,22 @@ func clnclnSetupWithConfig(t *testing.T, fundAmt, pushAmt uint64,
if err != nil {
t.Fatalf("lightningd.Run() got err %v", err)
}
err = lightningd.WaitForLog("peerswap initialized", testframework.TIMEOUT)
if err != nil {
t.Fatalf("lightningd.WaitForLog() got err %v", err)
var g errgroup.Group

g.Go(func() error {
return lightningd.WaitForLog("peerswap initialized", testframework.TIMEOUT)
})

g.Go(func() error {
err := lightningd.WaitForLog("Exited with error", 30)
if err == nil {
return fmt.Errorf("lightningd exited with error")
}
return nil
})

if err := g.Wait(); err != nil {
t.Fatalf("WaitForLog() got err %v", err)
}
}

Expand Down

0 comments on commit 644de2e

Please sign in to comment.