From 24b43e9a49dd2899a04addcf0858dc0fc8718ddd Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Mon, 18 May 2020 17:12:21 +0200 Subject: [PATCH] Use actor system as conf container (#1420) This seems to be recommended practice: https://doc.akka.io/docs/akka/current/general/actor-systems.html#configuration-container. As a nice side effect, it allows putting akka-related config in eclair.conf. Also, reorganize reference.conf/application.conf. --- eclair-core/src/main/resources/reference.conf | 18 +++++++++++ .../scala/fr/acinq/eclair/NodeParams.scala | 3 +- .../main/scala/fr/acinq/eclair/Setup.scala | 5 +-- .../eclair/integration/IntegrationSpec.scala | 10 ++---- .../scala/fr/acinq/eclair/JavafxBoot.scala | 7 ++-- .../scala/fr/acinq/eclair/gui/FxApp.scala | 5 +-- .../src/main/resources/application.conf | 32 ------------------- .../src/main/scala/fr/acinq/eclair/Boot.scala | 19 ++++++----- 8 files changed, 39 insertions(+), 60 deletions(-) diff --git a/eclair-core/src/main/resources/reference.conf b/eclair-core/src/main/resources/reference.conf index 8a356cf40..428706069 100644 --- a/eclair-core/src/main/resources/reference.conf +++ b/eclair-core/src/main/resources/reference.conf @@ -179,4 +179,22 @@ eclair { executor = "thread-pool-executor" type = PinnedDispatcher } +} + +akka { + io { + tcp { + # The maximum number of bytes delivered by a `Received` message. Before + # more data is read from the network the connection actor will try to + # do other work. + # The purpose of this setting is to impose a smaller limit than the + # configured receive buffer size. When using value 'unlimited' it will + # try to read all from the receive buffer. + # As per BOLT#8 lightning messages are at most 2 + 16 + 65535 + 16 = 65569bytes + # Currently the largest message is update_add_htlc (~1500b). + # As a tradeoff to reduce the RAM consumption, in conjunction with tcp pull mode, + # the default value is chosen to allow for a decent number of messages to be prefetched. + max-received-message-size = 16384b + } + } } \ No newline at end of file diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index 07b94be9c..6f31a65d0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -105,10 +105,9 @@ object NodeParams { * 3) Optionally provided config * 4) Default values in reference.conf */ - def loadConfiguration(datadir: File, overrideDefaults: Config = ConfigFactory.empty()) = + def loadConfiguration(datadir: File) = ConfigFactory.parseProperties(System.getProperties) .withFallback(ConfigFactory.parseFile(new File(datadir, "eclair.conf"))) - .withFallback(overrideDefaults) .withFallback(ConfigFactory.load()) def getSeed(datadir: File): ByteVector = { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index e595720a7..75f3f27c0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -65,12 +65,10 @@ import scala.util.{Failure, Success} * Created by PM on 25/01/2016. * * @param datadir directory where eclair-core will write/read its data. - * @param overrideDefaults use this parameter to programmatically override the node configuration . * @param seed_opt optional seed, if set eclair will use it instead of generating one and won't create a seed.dat file. * @param db optional databases to use, if not set eclair will create the necessary databases */ class Setup(datadir: File, - overrideDefaults: Config = ConfigFactory.empty(), seed_opt: Option[ByteVector] = None, db: Option[Databases] = None)(implicit system: ActorSystem) extends Logging { @@ -87,8 +85,7 @@ class Setup(datadir: File, secureRandom.nextInt() datadir.mkdirs() - val appConfig = NodeParams.loadConfiguration(datadir, overrideDefaults) - val config = appConfig.getConfig("eclair") + val config = system.settings.config.getConfig("eclair") val seed = seed_opt.getOrElse(NodeParams.getSeed(datadir)) val chain = config.getString("chain") val chaindir = new File(datadir, chain) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index f0c69ae15..65f8aad44 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.integration -import java.io.{File, PrintWriter} +import java.io.File import java.util.{Properties, UUID} import akka.actor.{ActorRef, ActorSystem} @@ -102,7 +102,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS "eclair.router.broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false, "eclair.to-remote-delay-blocks" -> 144, - "eclair.multi-part-payment-expiry" -> "20 seconds").asJava) + "eclair.multi-part-payment-expiry" -> "20 seconds").asJava).withFallback(ConfigFactory.load()) implicit val formats = DefaultFormats @@ -135,11 +135,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS def instantiateEclairNode(name: String, config: Config): Unit = { val datadir = new File(INTEGRATION_TMP_DIR, s"datadir-eclair-$name") datadir.mkdirs() - new PrintWriter(new File(datadir, "eclair.conf")) { - write(config.root().render()) - close() - } - implicit val system = ActorSystem(s"system-$name") + implicit val system = ActorSystem(s"system-$name", config) val setup = new Setup(datadir) val kit = Await.result(setup.bootstrap, 10 seconds) nodes = nodes + (name -> kit) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/JavafxBoot.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/JavafxBoot.scala index 9152e82ca..f3d95c4b7 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/JavafxBoot.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/JavafxBoot.scala @@ -27,15 +27,16 @@ import scala.concurrent.ExecutionContext.Implicits.global * Created by PM on 25/01/2016. */ object JavafxBoot extends App with Logging { - val datadir = new File(System.getProperty("eclair.datadir", System.getProperty("user.home") + "/.eclair")) try { + val datadir = new File(System.getProperty("eclair.datadir", System.getProperty("user.home") + "/.eclair")) + val config = NodeParams.loadConfiguration(datadir) val headless = System.getProperty("eclair.headless") != null if (headless) { - implicit val system = ActorSystem("eclair-node-gui") + implicit val system = ActorSystem("eclair-node-gui", config) val setup = new Setup(datadir) setup.bootstrap.map { kit => - Boot.startApiServiceIfEnabled(setup.config, kit) + Boot.startApiServiceIfEnabled(kit) } } else { System.setProperty("javafx.preloader", classOf[FxPreloader].getName) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala index a77ee3f1d..892d33107 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala @@ -82,7 +82,8 @@ class FxApp extends Application with Logging { mainFXML.setController(controller) val mainRoot = mainFXML.load[Parent] val datadir = new File(getParameters.getUnnamed.get(0)) - implicit val system = ActorSystem("eclair-node-gui") + val config = NodeParams.loadConfiguration(datadir) + implicit val system = ActorSystem("eclair-node-gui", config) val setup = new Setup(datadir) val unitConf = setup.config.getString("gui.unit") @@ -103,7 +104,7 @@ class FxApp extends Application with Logging { pKit.completeWith(setup.bootstrap) pKit.future.onComplete { case Success(kit) => - Boot.startApiServiceIfEnabled(setup.config, kit) + Boot.startApiServiceIfEnabled(kit) Platform.runLater(new Runnable { override def run(): Unit = { val scene = new Scene(mainRoot) diff --git a/eclair-node/src/main/resources/application.conf b/eclair-node/src/main/resources/application.conf index 6b18351a6..a55e28644 100644 --- a/eclair-node/src/main/resources/application.conf +++ b/eclair-node/src/main/resources/application.conf @@ -17,40 +17,8 @@ kamon.instrumentation.akka { } akka { - loggers = ["akka.event.slf4j.Slf4jLogger"] logger-startup-timeout = 30s loglevel = "DEBUG" # akka doc: You can enable DEBUG level for akka.loglevel and control the actual level in the SLF4J backend without any significant overhead, also for production. logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" - - io { - tcp { - - # The maximum number of bytes delivered by a `Received` message. Before - # more data is read from the network the connection actor will try to - # do other work. - # The purpose of this setting is to impose a smaller limit than the - # configured receive buffer size. When using value 'unlimited' it will - # try to read all from the receive buffer. - # As per BOLT#8 lightning messages are at most 2 + 16 + 65535 + 16 = 65569bytes - # Currently the largest message is update_add_htlc (~1500b). - # As a tradeoff to reduce the RAM consumption, in conjunction with tcp pull mode, - # the default value is chosen to allow for a decent number of messages to be prefetched. - max-received-message-size = 16384b - - } - } - - # Default maximum content length which should not be exceeded by incoming request entities. - # Can be changed at runtime (to a higher or lower value) via the `HttpEntity::withSizeLimit` method. - # Note that it is not necessarily a problem to set this to a high value as all stream operations - # are always properly backpressured. - # Nevertheless you might want to apply some limit in order to prevent a single client from consuming - # an excessive amount of server resources. - # - # Set to `infinite` to completely disable entity length checks. (Even then you can still apply one - # programmatically via `withSizeLimit`.) - # - # We disable the size check, because the batching bitcoin json-rpc client may return very large results - http.client.parsing.max-content-length=infinite } \ No newline at end of file diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/Boot.scala b/eclair-node/src/main/scala/fr/acinq/eclair/Boot.scala index 664f08009..522ae9219 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/Boot.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/Boot.scala @@ -21,7 +21,6 @@ import java.io.File import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.stream.{ActorMaterializer, BindFailedException} -import com.typesafe.config.Config import fr.acinq.eclair.api.Service import grizzled.slf4j.Logging import kamon.Kamon @@ -33,24 +32,24 @@ import scala.util.{Failure, Success} * Created by PM on 25/01/2016. */ object Boot extends App with Logging { - - val datadir = new File(System.getProperty("eclair.datadir", System.getProperty("user.home") + "/.eclair")) - try { + val datadir = new File(System.getProperty("eclair.datadir", System.getProperty("user.home") + "/.eclair")) + val config = NodeParams.loadConfiguration(datadir) + val plugins = Plugin.loadPlugins(args.map(new File(_))) plugins.foreach(plugin => logger.info(s"loaded plugin ${plugin.getClass.getSimpleName}")) - implicit val system: ActorSystem = ActorSystem("eclair-node") + implicit val system: ActorSystem = ActorSystem("eclair-node", config) implicit val ec: ExecutionContext = system.dispatcher val setup = new Setup(datadir) - if (setup.config.getBoolean("enable-kamon")) { - Kamon.init(setup.appConfig) + if (config.getBoolean("eclair.enable-kamon")) { + Kamon.init(config) } plugins.foreach(_.onSetup(setup)) setup.bootstrap onComplete { case Success(kit) => - startApiServiceIfEnabled(setup.config, kit) + startApiServiceIfEnabled(kit) plugins.foreach(_.onKit(kit)) case Failure(t) => onError(t) } @@ -61,12 +60,12 @@ object Boot extends App with Logging { /** * Starts the http APIs service if enabled in the configuration * - * @param config * @param kit * @param system * @param ec */ - def startApiServiceIfEnabled(config: Config, kit: Kit)(implicit system: ActorSystem, ec: ExecutionContext) = { + def startApiServiceIfEnabled(kit: Kit)(implicit system: ActorSystem, ec: ExecutionContext) = { + val config = system.settings.config.getConfig("eclair") if(config.getBoolean("api.enabled")){ logger.info(s"json API enabled on port=${config.getInt("api.port")}") implicit val materializer = ActorMaterializer()