<commit_before>/*
 * Copyright 2019 ACINQ SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.acinq.eclair

import com.typesafe.config.{Config, ConfigFactory, ConfigValueType}
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Satoshi}
import fr.acinq.eclair.Setup.Seeds
import fr.acinq.eclair.blockchain.fee._
import fr.acinq.eclair.channel.ChannelFlags
import fr.acinq.eclair.channel.fsm.Channel
import fr.acinq.eclair.channel.fsm.Channel.{ChannelConf, UnhandledExceptionStrategy}
import fr.acinq.eclair.crypto.Noise.KeyPair
import fr.acinq.eclair.crypto.keymanager.{ChannelKeyManager, NodeKeyManager}
import fr.acinq.eclair.db._
import fr.acinq.eclair.io.MessageRelay.{NoRelay, RelayAll, RelayChannelsOnly, RelayPolicy}
import fr.acinq.eclair.io.PeerConnection
import fr.acinq.eclair.message.OnionMessages.OnionMessageConfig
import fr.acinq.eclair.payment.relay.Relayer.{RelayFees, RelayParams}
import fr.acinq.eclair.router.Graph.{HeuristicsConstants, WeightRatios}
import fr.acinq.eclair.router.PathFindingExperimentConf
import fr.acinq.eclair.router.Router.{MultiPartParams, PathFindingConf, RouterConf, SearchBoundaries}
import fr.acinq.eclair.tor.Socks5ProxyParams
import fr.acinq.eclair.wire.protocol.{Color, EncodingType, NodeAddress}
import grizzled.slf4j.Logging
import scodec.bits.ByteVector

import java.io.File
import java.net.InetSocketAddress
import java.nio.file.Files
import java.util.UUID
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration._
import scala.jdk.CollectionConverters._

/**
 * Created by PM on 26/02/2017.
 */
case class NodeParams(nodeKeyManager: NodeKeyManager,
                      channelKeyManager: ChannelKeyManager,
                      instanceId: UUID, // a unique instance ID regenerated after each restart
                      private val blockHeight: AtomicLong,
                      alias: String,
                      color: Color,
                      publicAddresses: List[NodeAddress],
                      torAddress_opt: Option[NodeAddress],
                      features: Features[Feature],
                      private val overrideInitFeatures: Map[PublicKey, Features[InitFeature]],
                      syncWhitelist: Set[PublicKey],
                      pluginParams: Seq[PluginParams],
                      channelConf: ChannelConf,
                      onChainFeeConf: OnChainFeeConf,
                      relayParams: RelayParams,
                      db: Databases,
                      autoReconnect: Boolean,
                      initialRandomReconnectDelay: FiniteDuration,
                      maxReconnectInterval: FiniteDuration,
                      chainHash: ByteVector32,
                      invoiceExpiry: FiniteDuration,
                      multiPartPaymentExpiry: FiniteDuration,
                      peerConnectionConf: PeerConnection.Conf,
                      routerConf: RouterConf,
                      socksProxy_opt: Option[Socks5ProxyParams],
                      maxPaymentAttempts: Int,
                      enableTrampolinePayment: Boolean,
                      balanceCheckInterval: FiniteDuration,
                      blockchainWatchdogThreshold: Int,
                      blockchainWatchdogSources: Seq[String],
                      onionMessageConfig: OnionMessageConfig,
                      purgeInvoicesInterval: Option[FiniteDuration]) {
  val privateKey: Crypto.PrivateKey = nodeKeyManager.nodeKey.privateKey

  val nodeId: PublicKey = nodeKeyManager.nodeId

  val keyPair: KeyPair = KeyPair(nodeId.value, privateKey.value)

  val pluginMessageTags: Set[Int] = pluginParams.collect { case p: CustomFeaturePlugin => p.messageTags }.toSet.flatten

  def currentBlockHeight: BlockHeight = BlockHeight(blockHeight.get)

  /** Returns the features that should be used in our init message with the given peer. */
  def initFeaturesFor(nodeId: PublicKey): Features[InitFeature] = overrideInitFeatures.getOrElse(nodeId, features).initFeatures()
}

object NodeParams extends Logging {

  // @formatter:off
  sealed trait WatcherType
  object BITCOIND extends WatcherType
  // @formatter:on

  /**
   * Order of precedence for the configuration parameters:
   * 1) Java environment variables (-D...)
   * 2) Configuration file eclair.conf
   * 3) Default values in reference.conf
   */
  def loadConfiguration(datadir: File): Config =
    ConfigFactory.systemProperties()
      .withFallback(ConfigFactory.parseFile(new File(datadir, "eclair.conf")))
      .withFallback(ConfigFactory.load())

  private def readSeedFromFile(seedPath: File): ByteVector = {
    logger.info(s"use seed file: ${seedPath.getCanonicalPath}")
    ByteVector(Files.readAllBytes(seedPath.toPath))
  }

  private def writeSeedToFile(path: File, seed: ByteVector): Unit = {
    Files.write(path.toPath, seed.toArray)
    logger.info(s"create new seed file: ${path.getCanonicalPath}")
  }

  private def migrateSeedFile(source: File, destination: File): Unit = {
    if (source.exists() && !destination.exists()) {
      Files.copy(source.toPath, destination.toPath)
      logger.info(s"migrate seed file: ${source.getCanonicalPath} → ${destination.getCanonicalPath}")<commit_msg>Call `resolve()` on configuration (#2339)<commit_after>/*
 * Copyright 2019 ACINQ SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.acinq.eclair

import com.typesafe.config.{Config, ConfigFactory, ConfigValueType}
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Satoshi}
import fr.acinq.eclair.Setup.Seeds
import fr.acinq.eclair.blockchain.fee._
import fr.acinq.eclair.channel.ChannelFlags
import fr.acinq.eclair.channel.fsm.Channel
import fr.acinq.eclair.channel.fsm.Channel.{ChannelConf, UnhandledExceptionStrategy}
import fr.acinq.eclair.crypto.Noise.KeyPair
import fr.acinq.eclair.crypto.keymanager.{ChannelKeyManager, NodeKeyManager}
import fr.acinq.eclair.db._
import fr.acinq.eclair.io.MessageRelay.{NoRelay, RelayAll, RelayChannelsOnly, RelayPolicy}
import fr.acinq.eclair.io.PeerConnection
import fr.acinq.eclair.message.OnionMessages.OnionMessageConfig
import fr.acinq.eclair.payment.relay.Relayer.{RelayFees, RelayParams}
import fr.acinq.eclair.router.Graph.{HeuristicsConstants, WeightRatios}
import fr.acinq.eclair.router.PathFindingExperimentConf
import fr.acinq.eclair.router.Router.{MultiPartParams, PathFindingConf, RouterConf, SearchBoundaries}
import fr.acinq.eclair.tor.Socks5ProxyParams
import fr.acinq.eclair.wire.protocol.{Color, EncodingType, NodeAddress}
import grizzled.slf4j.Logging
import scodec.bits.ByteVector

import java.io.File
import java.net.InetSocketAddress
import java.nio.file.Files
import java.util.UUID
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration._
import scala.jdk.CollectionConverters._

/**
 * Created by PM on 26/02/2017.
 */
case class NodeParams(nodeKeyManager: NodeKeyManager,
                      channelKeyManager: ChannelKeyManager,
                      instanceId: UUID, // a unique instance ID regenerated after each restart
                      private val blockHeight: AtomicLong,
                      alias: String,
                      color: Color,
                      publicAddresses: List[NodeAddress],
                      torAddress_opt: Option[NodeAddress],
                      features: Features[Feature],
                      private val overrideInitFeatures: Map[PublicKey, Features[InitFeature]],
                      syncWhitelist: Set[PublicKey],
                      pluginParams: Seq[PluginParams],
                      channelConf: ChannelConf,
                      onChainFeeConf: OnChainFeeConf,
                      relayParams: RelayParams,
                      db: Databases,
                      autoReconnect: Boolean,
                      initialRandomReconnectDelay: FiniteDuration,
                      maxReconnectInterval: FiniteDuration,
                      chainHash: ByteVector32,
                      invoiceExpiry: FiniteDuration,
                      multiPartPaymentExpiry: FiniteDuration,
                      peerConnectionConf: PeerConnection.Conf,
                      routerConf: RouterConf,
                      socksProxy_opt: Option[Socks5ProxyParams],
                      maxPaymentAttempts: Int,
                      enableTrampolinePayment: Boolean,
                      balanceCheckInterval: FiniteDuration,
                      blockchainWatchdogThreshold: Int,
                      blockchainWatchdogSources: Seq[String],
                      onionMessageConfig: OnionMessageConfig,
                      purgeInvoicesInterval: Option[FiniteDuration]) {
  val privateKey: Crypto.PrivateKey = nodeKeyManager.nodeKey.privateKey

  val nodeId: PublicKey = nodeKeyManager.nodeId

  val keyPair: KeyPair = KeyPair(nodeId.value, privateKey.value)

  val pluginMessageTags: Set[Int] = pluginParams.collect { case p: CustomFeaturePlugin => p.messageTags }.toSet.flatten

  def currentBlockHeight: BlockHeight = BlockHeight(blockHeight.get)

  /** Returns the features that should be used in our init message with the given peer. */
  def initFeaturesFor(nodeId: PublicKey): Features[InitFeature] = overrideInitFeatures.getOrElse(nodeId, features).initFeatures()
}

object NodeParams extends Logging {

  // @formatter:off
  sealed trait WatcherType
  object BITCOIND extends WatcherType
  // @formatter:on

  /**
   * Order of precedence for the configuration parameters:
   * 1) Java environment variables (-D...)
   * 2) Configuration file eclair.conf
   * 3) Default values in reference.conf
   */
  def loadConfiguration(datadir: File): Config =
    ConfigFactory.systemProperties()
      .withFallback(ConfigFactory.parseFile(new File(datadir, "eclair.conf")))
      .withFallback(ConfigFactory.load())
      .resolve()

  private def readSeedFromFile(seedPath: File): ByteVector = {
    logger.info(s"use seed file: ${seedPath.getCanonicalPath}")
    ByteVector(Files.readAllBytes(seedPath.toPath))
  }

  private def writeSeedToFile(path: File, seed: ByteVector): Unit = {
    Files.write(path.toPath, seed.toArray)
    logger.info(s"create new seed file: ${path.getCanonicalPath}")
  }

  private def migrateSeedFile(source: File, destination: File): Unit = {
    if (source.exists() && !destination.exists()) {
      Files.copy(source.toPath, destination.toPath)
      logger.info(s"migrate seed file: ${source.getCanonicalPath} → ${destination.getCanonicalPath}")
{'fraction_non_alphanumeric': 0.08594617684750107, 'fraction_numerical': 0.004784280222127296, 'mean_word_length': 3.054728091444406, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4625039', 'n_tokens_mistral': 3381, 'n_tokens_neox': 3171, 'n_words': 760}