From 9e58d685cbed7c01651ef5953f4aa3a6a346dc0f Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Wed, 11 Jul 2018 18:13:57 +0900 Subject: [PATCH] Add LND support --- .../docker-fragments/bitcoin-clightning.yml | 2 +- .../docker-fragments/bitcoin-lnd.yml | 49 ++++ .../docker-fragments/btcpayserver.yml | 2 +- .../docker-fragments/litecoin-clightning.yml | 2 +- .../docker-fragments/litecoin-lnd.yml | 49 ++++ .../src/CryptoDefinition.cs | 20 +- .../src/DockerComposeDefinition.cs | 247 ++++++++++-------- docker-compose-generator/src/Program.cs | 6 +- 8 files changed, 250 insertions(+), 127 deletions(-) create mode 100644 docker-compose-generator/docker-fragments/bitcoin-lnd.yml create mode 100644 docker-compose-generator/docker-fragments/litecoin-lnd.yml diff --git a/docker-compose-generator/docker-fragments/bitcoin-clightning.yml b/docker-compose-generator/docker-fragments/bitcoin-clightning.yml index 02b12dd..6448743 100644 --- a/docker-compose-generator/docker-fragments/bitcoin-clightning.yml +++ b/docker-compose-generator/docker-fragments/bitcoin-clightning.yml @@ -23,7 +23,7 @@ services: - bitcoind btcpayserver: environment: - BTCPAY_BTCLIGHTNING: "/etc/clightning_bitcoin/lightning-rpc" + BTCPAY_BTCLIGHTNING: "type=clightning;server=unix://etc/clightning_bitcoin/lightning-rpc" volumes: - "clightning_bitcoin_datadir:/etc/clightning_bitcoin" links: diff --git a/docker-compose-generator/docker-fragments/bitcoin-lnd.yml b/docker-compose-generator/docker-fragments/bitcoin-lnd.yml new file mode 100644 index 0000000..270860e --- /dev/null +++ b/docker-compose-generator/docker-fragments/bitcoin-lnd.yml @@ -0,0 +1,49 @@ +version: "3" + +services: + lnd_bitcoin: + image: btcpayserver/lnd:0.4.2.0 + container_name: btcpayserver_lnd_bitcoin + environment: + LND_CHAIN: "btc" + LND_ENVIRONMENT: "${NBITCOIN_NETWORK:-regtest}" + LND_EXTRA_ARGS: | + restlisten=0.0.0.0:8080 + bitcoin.node=bitcoind + bitcoind.rpchost=bitcoind:43782 + bitcoind.zmqpath=tcp://bitcoind:28332 + externalip=${BTCPAY_HOST}:9735 + alias=${LIGHTNING_ALIAS} + noencryptwallet=1 + notls=1 + ports: + - "9735:9735" + expose: + - "8080" + - "9735" + volumes: + - "lnd_bitcoin_datadir:/data" + - "bitcoin_datadir:/deps/.bitcoin" + links: + - bitcoind + + btcpayserver: + environment: + BTCPAY_BTCLIGHTNING: "type=lnd-rest;server=http://lnd_bitcoin:8080/;macaroonfilepath=/etc/lnd_bitcoin/admin.macaroon;allowinsecure=true" + volumes: + - "lnd_bitcoin_datadir:/etc/lnd_bitcoin" + links: + - lnd_bitcoin + + bitcoind: + environment: + BITCOIN_EXTRA_ARGS: | + zmqpubrawtx=tcp://0.0.0.0:28332 + zmqpubrawblock=tcp://0.0.0.0:28332 + zmqpubrawtxlock=tcp://0.0.0.0:28332 + zmqpubhashblock=tcp://0.0.0.0:28332 + expose: + - "28332" + +volumes: + lnd_bitcoin_datadir: \ No newline at end of file diff --git a/docker-compose-generator/docker-fragments/btcpayserver.yml b/docker-compose-generator/docker-fragments/btcpayserver.yml index 2a534e4..8c7fed1 100644 --- a/docker-compose-generator/docker-fragments/btcpayserver.yml +++ b/docker-compose-generator/docker-fragments/btcpayserver.yml @@ -4,7 +4,7 @@ services: btcpayserver: restart: unless-stopped - image: nicolasdorier/btcpayserver:1.0.2.39 + image: nicolasdorier/btcpayserver:1.0.2.40 expose: - "49392" environment: diff --git a/docker-compose-generator/docker-fragments/litecoin-clightning.yml b/docker-compose-generator/docker-fragments/litecoin-clightning.yml index 3d06bb5..b0b38d1 100644 --- a/docker-compose-generator/docker-fragments/litecoin-clightning.yml +++ b/docker-compose-generator/docker-fragments/litecoin-clightning.yml @@ -23,7 +23,7 @@ services: - litecoind btcpayserver: environment: - BTCPAY_LTCLIGHTNING: "/etc/clightning_litecoin/lightning-rpc" + BTCPAY_LTCLIGHTNING: "type=clightning;server=unix://etc/clightning_litecoin/lightning-rpc" volumes: - "clightning_litecoin_datadir:/etc/clightning_litecoin" links: diff --git a/docker-compose-generator/docker-fragments/litecoin-lnd.yml b/docker-compose-generator/docker-fragments/litecoin-lnd.yml new file mode 100644 index 0000000..6d5998e --- /dev/null +++ b/docker-compose-generator/docker-fragments/litecoin-lnd.yml @@ -0,0 +1,49 @@ +version: "3" + +services: + lnd_litecoin: + image: btcpayserver/lnd:0.4.2.0 + container_name: btcpayserver_lnd_litecoin + environment: + LND_CHAIN: "ltc" + LND_ENVIRONMENT: "${NBITCOIN_NETWORK:-regtest}" + LND_EXTRA_ARGS: | + restlisten=0.0.0.0:8080 + litecoin.node=litecoind + litecoind.rpchost=litecoind:43782 + litecoind.zmqpath=tcp://litecoind:28332 + externalip=${BTCPAY_HOST}:9736 + alias=${LIGHTNING_ALIAS} + noencryptwallet=1 + notls=1 + ports: + - "9736:9735" + expose: + - "8080" + - "9736" + volumes: + - "lnd_litecoin_datadir:/data" + - "litecoin_datadir:/deps/.litecoin" + links: + - litecoind + + btcpayserver: + environment: + BTCPAY_LTCLIGHTNING: "type=lnd-rest;server=http://lnd_litecoin:8080/;macaroonfilepath=/etc/lnd_litecoin/admin.macaroon;allowinsecure=true" + volumes: + - "lnd_litecoin_datadir:/etc/lnd_litecoin" + links: + - lnd_litecoin + + litecoind: + environment: + BITCOIN_EXTRA_ARGS: | + zmqpubrawtx=tcp://0.0.0.0:28332 + zmqpubrawblock=tcp://0.0.0.0:28332 + zmqpubrawtxlock=tcp://0.0.0.0:28332 + zmqpubhashblock=tcp://0.0.0.0:28332 + expose: + - "28332" + +volumes: + lnd_litecoin_datadir: \ No newline at end of file diff --git a/docker-compose-generator/src/CryptoDefinition.cs b/docker-compose-generator/src/CryptoDefinition.cs index 70491e9..879c17b 100644 --- a/docker-compose-generator/src/CryptoDefinition.cs +++ b/docker-compose-generator/src/CryptoDefinition.cs @@ -21,8 +21,13 @@ namespace DockerGenerator get; private set; } + public string LNDFragment + { + get; + private set; + } - public static CryptoDefinition[] GetDefinitions() + public static CryptoDefinition[] GetDefinitions() { return new[] { @@ -31,30 +36,29 @@ namespace DockerGenerator Crypto = "ltc", CryptoFragment = "litecoin", CLightningFragment = "litecoin-clightning", - }, + LNDFragment = "litecoin-lnd" + }, new CryptoDefinition() { Crypto = "btc", CryptoFragment = "bitcoin", CLightningFragment = "bitcoin-clightning", + LNDFragment = "bitcoin-lnd" }, new CryptoDefinition() { Crypto = "btg", - CryptoFragment = "bgold", - CLightningFragment = null, + CryptoFragment = "bgold" }, new CryptoDefinition() { Crypto = "ftc", - CryptoFragment = "feathercoin", - CLightningFragment = null, + CryptoFragment = "feathercoin" }, new CryptoDefinition() { Crypto = "grs", - CryptoFragment = "groestlcoin", - CLightningFragment = null, + CryptoFragment = "groestlcoin" } }; } diff --git a/docker-compose-generator/src/DockerComposeDefinition.cs b/docker-compose-generator/src/DockerComposeDefinition.cs index 439808d..5fbdef8 100644 --- a/docker-compose-generator/src/DockerComposeDefinition.cs +++ b/docker-compose-generator/src/DockerComposeDefinition.cs @@ -8,128 +8,145 @@ using System.IO; namespace DockerGenerator { - public class DockerComposeDefinition - { - public List Fragments - { - get; set; - } - private string _Name; + public class DockerComposeDefinition + { + public List Fragments + { + get; set; + } + private string _Name; - public DockerComposeDefinition(string name, List fragments) - { - Fragments = fragments; - _Name = name; - } + public DockerComposeDefinition(string name, List fragments) + { + Fragments = fragments; + _Name = name; + } - public string FragmentLocation - { - get; set; - } - public string BuildOutputDirectory - { - get; set; - } + public string FragmentLocation + { + get; set; + } + public string BuildOutputDirectory + { + get; set; + } - public string GetFilePath() - { - return Path.Combine(BuildOutputDirectory, $"docker-compose.{_Name}.yml"); - } - public void Build() - { - Console.WriteLine($"Generating {GetFilePath()}"); - var deserializer = new DeserializerBuilder().Build(); - var serializer = new SerializerBuilder().Build(); + public string GetFilePath() + { + return Path.Combine(BuildOutputDirectory, $"docker-compose.{_Name}.yml"); + } + public void Build() + { + Console.WriteLine($"Generating {GetFilePath()}"); + var deserializer = new DeserializerBuilder().Build(); + var serializer = new SerializerBuilder().Build(); - Console.WriteLine($"With fragments:"); - foreach(var fragment in Fragments) - { - Console.WriteLine($"\t{fragment}"); - } - var services = new List>(); - var volumes = new List>(); + Console.WriteLine($"With fragments:"); + foreach(var fragment in Fragments) + { + Console.WriteLine($"\t{fragment}"); + } + var services = new List>(); + var volumes = new List>(); - foreach(var doc in Fragments.Select(f => ParseDocument(f))) - { - if(doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot) - { - services.AddRange(fragmentServicesRoot.Children); - } + foreach(var doc in Fragments.Select(f => ParseDocument(f))) + { + if(doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot) + { + services.AddRange(fragmentServicesRoot.Children); + } - if(doc.Children.ContainsKey("volumes") && doc.Children["volumes"] is YamlMappingNode fragmentVolumesRoot) - { - volumes.AddRange(fragmentVolumesRoot.Children); - } - } + if(doc.Children.ContainsKey("volumes") && doc.Children["volumes"] is YamlMappingNode fragmentVolumesRoot) + { + volumes.AddRange(fragmentVolumesRoot.Children); + } + } - - YamlMappingNode output = new YamlMappingNode(); - output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted }); - output.Add("services", new YamlMappingNode(Merge(services))); - output.Add("volumes", new YamlMappingNode(volumes)); - var result = serializer.Serialize(output); - var outputFile = GetFilePath(); - File.WriteAllText(outputFile, result.Replace("''", "")); - Console.WriteLine($"Generated {outputFile}"); - Console.WriteLine(); - } - private KeyValuePair[] Merge(List> services) - { - return services - .GroupBy(s => s.Key.ToString(), s=> s.Value) - .Select(group => - (GroupName: group.Key, - MainNode: group.OfType().Single(n=> n.Children.ContainsKey("image")), - MergedNodes: group.OfType().Where(n => !n.Children.ContainsKey("image")))) - .Select(_ => - { - foreach(var node in _.MergedNodes) - { - foreach(var child in node) - { - var childValue = child.Value; - if(!_.MainNode.Children.TryGetValue(child.Key, out var mainChildValue)) - { - mainChildValue = child.Value; - _.MainNode.Add(child.Key, child.Value); - } - else if(childValue is YamlMappingNode childMapping && mainChildValue is YamlMappingNode mainChildMapping) - { - foreach(var leaf in childMapping) - { - if(mainChildMapping.Children.TryGetValue(leaf.Key, out var mainLeaf)) - { - if(leaf.Value is YamlScalarNode leafScalar && mainLeaf is YamlScalarNode leafMainScalar) - { - leafMainScalar.Value = leafMainScalar.Value + "," + leaf.Value; - } - } - else - { - mainChildMapping.Add(leaf.Key, leaf.Value); - } - } - } - else if(childValue is YamlSequenceNode childSequence && mainChildValue is YamlSequenceNode mainSequence) - { - foreach(var c in childSequence.Children) - { - mainSequence.Add(c); - } - } - } - } - return new KeyValuePair(_.GroupName, _.MainNode); - }).ToArray(); - } + YamlMappingNode output = new YamlMappingNode(); + output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted }); + output.Add("services", new YamlMappingNode(Merge(services))); + output.Add("volumes", new YamlMappingNode(volumes)); + var result = serializer.Serialize(output); + var outputFile = GetFilePath(); + File.WriteAllText(outputFile, result.Replace("''", "")); + Console.WriteLine($"Generated {outputFile}"); + Console.WriteLine(); + } - private YamlMappingNode ParseDocument(string fragment) - { - var input = new StringReader(File.ReadAllText(Path.Combine(FragmentLocation, $"{fragment}.yml"))); - YamlStream stream = new YamlStream(); - stream.Load(input); - return (YamlMappingNode)stream.Documents[0].RootNode; - } - } + private KeyValuePair[] Merge(List> services) + { + return services + .GroupBy(s => s.Key.ToString(), s => s.Value) + .Select(group => + (GroupName: group.Key, + MainNode: group.OfType().Single(n => n.Children.ContainsKey("image")), + MergedNodes: group.OfType().Where(n => !n.Children.ContainsKey("image")))) + .Select(_ => + { + foreach(var node in _.MergedNodes) + { + foreach(var child in node) + { + var childValue = child.Value; + if(!_.MainNode.Children.TryGetValue(child.Key, out var mainChildValue)) + { + mainChildValue = child.Value; + _.MainNode.Add(child.Key, child.Value); + } + else if(childValue is YamlMappingNode childMapping && mainChildValue is YamlMappingNode mainChildMapping) + { + foreach(var leaf in childMapping) + { + if(mainChildMapping.Children.TryGetValue(leaf.Key, out var mainLeaf)) + { + if(leaf.Value is YamlScalarNode leafScalar && mainLeaf is YamlScalarNode leafMainScalar) + { + var eof = EOF(leafMainScalar.Value) ?? EOF(leaf.Value.ToString()); + if(eof != null) + { + leafMainScalar.Value = leafMainScalar.Value + eof + leaf.Value; + } + else + { + leafMainScalar.Value = leafMainScalar.Value + "," + leaf.Value; + } + } + } + else + { + mainChildMapping.Add(leaf.Key, leaf.Value); + } + } + } + else if(childValue is YamlSequenceNode childSequence && mainChildValue is YamlSequenceNode mainSequence) + { + foreach(var c in childSequence.Children) + { + mainSequence.Add(c); + } + } + } + } + return new KeyValuePair(_.GroupName, _.MainNode); + }).ToArray(); + } + + private string EOF(string value) + { + if(value.Contains("\r\n", StringComparison.OrdinalIgnoreCase)) + return "\r\n"; + if(value.Contains("\n", StringComparison.OrdinalIgnoreCase)) + return "\n"; + return null; + } + + private YamlMappingNode ParseDocument(string fragment) + { + var input = new StringReader(File.ReadAllText(Path.Combine(FragmentLocation, $"{fragment}.yml"))); + YamlStream stream = new YamlStream(); + stream.Load(input); + return (YamlMappingNode)stream.Documents[0].RootNode; + } + } } diff --git a/docker-compose-generator/src/Program.cs b/docker-compose-generator/src/Program.cs index 6e35bd9..ba88ead 100644 --- a/docker-compose-generator/src/Program.cs +++ b/docker-compose-generator/src/Program.cs @@ -86,7 +86,11 @@ namespace DockerGenerator { fragments.Add(crypto.CLightningFragment); } - } + if(composition.SelectedLN == "lnd" && crypto.LNDFragment != null) + { + fragments.Add(crypto.LNDFragment); + } + } var def = new DockerComposeDefinition(name, fragments); def.FragmentLocation = fragmentLocation;