diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/DBCompatChecker.scala b/eclair-core/src/main/scala/fr/acinq/eclair/DBCompatChecker.scala index fa05f0770..b9b22abaa 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/DBCompatChecker.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/DBCompatChecker.scala @@ -28,7 +28,7 @@ object DBCompatChecker extends Logging { * @param nodeParams */ def checkDBCompatibility(nodeParams: NodeParams): Unit = - Try(nodeParams.channelsDb.listChannels()) match { + Try(nodeParams.db.channels.listLocalChannels()) match { case Success(_) => {} case Failure(_) => throw IncompatibleDBException } @@ -39,7 +39,7 @@ object DBCompatChecker extends Logging { * @param nodeParams */ def checkNetworkDBCompatibility(nodeParams: NodeParams): Unit = - Try(nodeParams.networkDb.listChannels(), nodeParams.networkDb.listNodes(), nodeParams.networkDb.listChannelUpdates()) match { + Try(nodeParams.db.network.listChannels(), nodeParams.db.network.listNodes(), nodeParams.db.network.listChannelUpdates()) match { case Success(_) => {} case Failure(_) => throw IncompatibleNetworkDBException } 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 6eb78f165..a6b06c953 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -61,12 +61,7 @@ case class NodeParams(keyManager: KeyManager, feeProportionalMillionth: Int, reserveToFundingRatio: Double, maxReserveToFundingRatio: Double, - channelsDb: ChannelsDb, - peersDb: PeersDb, - networkDb: NetworkDb, - pendingRelayDb: PendingRelayDb, - paymentsDb: PaymentsDb, - auditDb: AuditDb, + db: Databases, revocationTimeout: FiniteDuration, pingInterval: FiniteDuration, pingTimeout: FiniteDuration, @@ -129,29 +124,11 @@ object NodeParams { } } - def makeNodeParams(datadir: File, config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress]): NodeParams = { - - datadir.mkdirs() + def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases): NodeParams = { val chain = config.getString("chain") val chainHash = makeChainHash(chain) - val chaindir = new File(datadir, chain) - chaindir.mkdir() - - val sqlite = DriverManager.getConnection(s"jdbc:sqlite:${new File(chaindir, "eclair.sqlite")}") - SqliteUtils.obtainExclusiveLock(sqlite) // there should only be one process writing to this file - val channelsDb = new SqliteChannelsDb(sqlite) - val peersDb = new SqlitePeersDb(sqlite) - val pendingRelayDb = new SqlitePendingRelayDb(sqlite) - val paymentsDb = new SqlitePaymentsDb(sqlite) - - val sqliteNetwork = DriverManager.getConnection(s"jdbc:sqlite:${new File(chaindir, "network.sqlite")}") - val networkDb = new SqliteNetworkDb(sqliteNetwork) - - val sqliteAudit = DriverManager.getConnection(s"jdbc:sqlite:${new File(chaindir, "audit.sqlite")}") - val auditDb = new SqliteAuditDb(sqliteAudit) - val color = ByteVector.fromValidHex(config.getString("node-color")) require(color.size == 3, "color should be a 3-bytes hex buffer") @@ -220,12 +197,7 @@ object NodeParams { feeProportionalMillionth = config.getInt("fee-proportional-millionths"), reserveToFundingRatio = config.getDouble("reserve-to-funding-ratio"), maxReserveToFundingRatio = config.getDouble("max-reserve-to-funding-ratio"), - channelsDb = channelsDb, - peersDb = peersDb, - networkDb = networkDb, - pendingRelayDb = pendingRelayDb, - paymentsDb = paymentsDb, - auditDb = auditDb, + db = database, revocationTimeout = FiniteDuration(config.getDuration("revocation-timeout").getSeconds, TimeUnit.SECONDS), pingInterval = FiniteDuration(config.getDuration("ping-interval").getSeconds, TimeUnit.SECONDS), pingTimeout = FiniteDuration(config.getDuration("ping-timeout").getSeconds, TimeUnit.SECONDS), 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 ffe2c095d..3cbaecdbf 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -43,6 +43,7 @@ import fr.acinq.eclair.blockchain.fee.{ConstantFeeProvider, _} import fr.acinq.eclair.blockchain.{EclairWallet, _} import fr.acinq.eclair.channel.Register import fr.acinq.eclair.crypto.LocalKeyManager +import fr.acinq.eclair.db.Databases import fr.acinq.eclair.io.{Authenticator, Server, Switchboard} import fr.acinq.eclair.payment._ import fr.acinq.eclair.router._ @@ -67,7 +68,14 @@ import scala.concurrent.duration._ */ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), - seed_opt: Option[ByteVector] = None)(implicit system: ActorSystem) extends Logging { + seed_opt: Option[ByteVector] = None, + db: Option[Databases] = None)(implicit system: ActorSystem) extends Logging { + + implicit val materializer = ActorMaterializer() + implicit val timeout = Timeout(30 seconds) + implicit val formats = org.json4s.DefaultFormats + implicit val ec = ExecutionContext.Implicits.global + implicit val sttpBackend = OkHttpFutureBackend() logger.info(s"hello!") logger.info(s"version=${getClass.getPackage.getImplementationVersion} commit=${getClass.getPackage.getSpecificationVersion}") @@ -76,17 +84,18 @@ class Setup(datadir: File, // this will force the secure random instance to initialize itself right now, making sure it doesn't hang later (see comment in package.scala) secureRandom.nextInt() + datadir.mkdirs() val config = NodeParams.loadConfiguration(datadir, overrideDefaults) val seed = seed_opt.getOrElse(NodeParams.getSeed(datadir)) val chain = config.getString("chain") val keyManager = new LocalKeyManager(seed, NodeParams.makeChainHash(chain)) - implicit val materializer = ActorMaterializer() - implicit val timeout = Timeout(30 seconds) - implicit val formats = org.json4s.DefaultFormats - implicit val ec = ExecutionContext.Implicits.global - implicit val sttpBackend = OkHttpFutureBackend() - val nodeParams = NodeParams.makeNodeParams(datadir, config, keyManager, initTor()) + val database = db match { + case Some(d) => d + case None => Databases.sqliteJDBC(new File(datadir, chain)) + } + + val nodeParams = NodeParams.makeNodeParams(config, keyManager, initTor(), database) val serverBindingAddress = new InetSocketAddress( config.getString("server.binding-ip"), diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/api/Service.scala b/eclair-core/src/main/scala/fr/acinq/eclair/api/Service.scala index f90e54b7b..69a078bb1 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/api/Service.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/api/Service.scala @@ -321,9 +321,9 @@ trait Service extends Logging { case _ => (0L, Long.MaxValue) } completeRpcFuture(req.id, Future(AuditResponse( - sent = nodeParams.auditDb.listSent(from, to), - received = nodeParams.auditDb.listReceived(from, to), - relayed = nodeParams.auditDb.listRelayed(from, to)) + sent = nodeParams.db.audit.listSent(from, to), + received = nodeParams.db.audit.listReceived(from, to), + relayed = nodeParams.db.audit.listRelayed(from, to)) )) case "networkfees" => @@ -331,10 +331,10 @@ trait Service extends Logging { case JInt(from) :: JInt(to) :: Nil => (from.toLong, to.toLong) case _ => (0L, Long.MaxValue) } - completeRpcFuture(req.id, Future(nodeParams.auditDb.listNetworkFees(from, to))) + completeRpcFuture(req.id, Future(nodeParams.db.audit.listNetworkFees(from, to))) // retrieve fee stats - case "channelstats" => completeRpcFuture(req.id, Future(nodeParams.auditDb.stats)) + case "channelstats" => completeRpcFuture(req.id, Future(nodeParams.db.audit.stats)) // method name was not found diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala index ed2050a68..1840b89c5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -645,7 +645,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu trimmedHtlcs collect { case DirectedHtlc(_, u) => log.info(s"adding paymentHash=${u.paymentHash} cltvExpiry=${u.cltvExpiry} to htlcs db for commitNumber=$nextCommitNumber") - nodeParams.channelsDb.addOrUpdateHtlcInfo(d.channelId, nextCommitNumber, u.paymentHash, u.cltvExpiry) + nodeParams.db.channels.addOrUpdateHtlcInfo(d.channelId, nextCommitNumber, u.paymentHash, u.cltvExpiry) } if (!Helpers.aboveReserve(d.commitments) && Helpers.aboveReserve(commitments1)) { // we just went above reserve (can't go below), let's refresh our channel_update to enable/disable it accordingly @@ -1300,7 +1300,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu stateData match { case d: HasCommitments => log.info(s"deleting database record for channelId=${d.channelId}") - nodeParams.channelsDb.removeChannel(d.channelId) + nodeParams.db.channels.removeChannel(d.channelId) case _ => {} } log.info("shutting down") @@ -1895,7 +1895,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu def handleRemoteSpentOther(tx: Transaction, d: HasCommitments) = { log.warning(s"funding tx spent in txid=${tx.txid}") - Helpers.Closing.claimRevokedRemoteCommitTxOutputs(keyManager, d.commitments, tx, nodeParams.channelsDb) match { + Helpers.Closing.claimRevokedRemoteCommitTxOutputs(keyManager, d.commitments, tx, nodeParams.db.channels) match { case Some(revokedCommitPublished) => log.warning(s"txid=${tx.txid} was a revoked commitment, publishing the penalty tx") val exc = FundingTxSpent(d.channelId, tx) @@ -2053,7 +2053,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu def store[T](d: T)(implicit tp: T <:< HasCommitments): T = { log.debug(s"updating database record for channelId={}", d.channelId) - nodeParams.channelsDb.addOrUpdateChannel(d) + nodeParams.db.channels.addOrUpdateChannel(d) context.system.eventStream.publish(ChannelPersisted(self, remoteNodeId, d.channelId, d)) d } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/ChannelsDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/ChannelsDb.scala index 86e20a4aa..7f531280d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/ChannelsDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/ChannelsDb.scala @@ -25,7 +25,7 @@ trait ChannelsDb { def removeChannel(channelId: ByteVector32) - def listChannels(): Seq[HasCommitments] + def listLocalChannels(): Seq[HasCommitments] def addOrUpdateHtlcInfo(channelId: ByteVector32, commitmentNumber: Long, paymentHash: ByteVector32, cltvExpiry: Long) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala new file mode 100644 index 000000000..ff2badd0a --- /dev/null +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala @@ -0,0 +1,50 @@ +package fr.acinq.eclair.db + +import java.io.File +import java.sql.{Connection, DriverManager} + +import fr.acinq.eclair.db.sqlite._ + +trait Databases { + + val network: NetworkDb + + val audit: AuditDb + + val channels: ChannelsDb + + val peers: PeersDb + + val payments: PaymentsDb + + val pendingRelay: PendingRelayDb + +} + +object Databases { + + /** + * Given a parent folder it creates or loads all the databases from a JDBC connection + * @param dbdir + * @return + */ + def sqliteJDBC(dbdir: File): Databases = { + dbdir.mkdir() + val sqliteEclair = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "eclair.sqlite")}") + val sqliteNetwork = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "network.sqlite")}") + val sqliteAudit = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "audit.sqlite")}") + SqliteUtils.obtainExclusiveLock(sqliteEclair) // there should only be one process writing to this file + + databaseByConnections(sqliteAudit, sqliteNetwork, sqliteEclair) + } + + def databaseByConnections(auditJdbc: Connection, networkJdbc: Connection, eclairJdbc: Connection) = new Databases { + override val network = new SqliteNetworkDb(networkJdbc) + override val audit = new SqliteAuditDb(auditJdbc) + override val channels = new SqliteChannelsDb(eclairJdbc) + override val peers = new SqlitePeersDb(eclairJdbc) + override val payments = new SqlitePaymentsDb(eclairJdbc) + override val pendingRelay = new SqlitePendingRelayDb(eclairJdbc) + } + +} \ No newline at end of file diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteChannelsDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteChannelsDb.scala index 0ccc2fb2f..fdc10418f 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteChannelsDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteChannelsDb.scala @@ -73,7 +73,7 @@ class SqliteChannelsDb(sqlite: Connection) extends ChannelsDb { } } - override def listChannels(): Seq[HasCommitments] = { + override def listLocalChannels(): Seq[HasCommitments] = { using(sqlite.createStatement) { statement => val rs = statement.executeQuery("SELECT data FROM local_channels") codecSequence(rs, stateDataCodec) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index e8c261a83..f58f60101 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -95,7 +95,7 @@ class Peer(nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: Actor val address_opt = if (outgoing) { // we store the node address upon successful outgoing connection, so we can reconnect later // any previous address is overwritten - NodeAddress.fromParts(address.getHostString, address.getPort).map(nodeAddress => nodeParams.peersDb.addOrUpdatePeer(remoteNodeId, nodeAddress)) + NodeAddress.fromParts(address.getHostString, address.getPort).map(nodeAddress => nodeParams.db.peers.addOrUpdatePeer(remoteNodeId, nodeAddress)) Some(address) } else None @@ -489,7 +489,7 @@ class Peer(nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: Actor def stopPeer() = { log.info("removing peer from db") - nodeParams.peersDb.removePeer(remoteNodeId) + nodeParams.db.peers.removePeer(remoteNodeId) stop(FSM.Normal) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala index 6801112a6..c2b6cf0b1 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala @@ -44,8 +44,8 @@ class Switchboard(nodeParams: NodeParams, authenticator: ActorRef, watcher: Acto // we load peers and channels from database { - val channels = nodeParams.channelsDb.listChannels() - val peers = nodeParams.peersDb.listPeers() + val channels = nodeParams.db.channels.listLocalChannels() + val peers = nodeParams.db.peers.listPeers() checkBrokenHtlcsLink(channels, nodeParams.privateKey) match { case Nil => () diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Auditor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Auditor.scala index 38514c9ee..76eeb4d1c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Auditor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Auditor.scala @@ -27,7 +27,7 @@ import scala.concurrent.duration._ class Auditor(nodeParams: NodeParams) extends Actor with ActorLogging { - val db = nodeParams.auditDb + val db = nodeParams.db.audit context.system.eventStream.subscribe(self, classOf[PaymentEvent]) context.system.eventStream.subscribe(self, classOf[NetworkFeePaid]) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/CommandBuffer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/CommandBuffer.scala index 14336f3bd..37c6c5dd3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/CommandBuffer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/CommandBuffer.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.channel._ class CommandBuffer(nodeParams: NodeParams, register: ActorRef) extends Actor with ActorLogging { import CommandBuffer._ - import nodeParams.pendingRelayDb + import nodeParams.db._ context.system.eventStream.subscribe(self, classOf[ChannelStateChanged]) @@ -34,17 +34,17 @@ class CommandBuffer(nodeParams: NodeParams, register: ActorRef) extends Actor wi // save command in db register forward Register.Forward(channelId, cmd) // we also store the preimage in a db (note that this happens *after* forwarding the fulfill to the channel, so we don't add latency) - pendingRelayDb.addPendingRelay(channelId, htlcId, cmd) + pendingRelay.addPendingRelay(channelId, htlcId, cmd) case CommandAck(channelId, htlcId) => //delete from db log.debug(s"fulfill/fail acked for channelId=$channelId htlcId=$htlcId") - pendingRelayDb.removePendingRelay(channelId, htlcId) + pendingRelay.removePendingRelay(channelId, htlcId) case ChannelStateChanged(channel, _, _, WAIT_FOR_INIT_INTERNAL | OFFLINE | SYNCING, NORMAL | SHUTDOWN | CLOSING, d: HasCommitments) => import d.channelId // if channel is in a state where it can have pending htlcs, we send them the fulfills we know of - pendingRelayDb.listPendingRelay(channelId) match { + pendingRelay.listPendingRelay(channelId) match { case Nil => () case msgs => log.info(s"re-sending ${msgs.size} unacked fulfills/fails to channel $channelId") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala index 940359e98..cbf9b7947 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala @@ -65,7 +65,7 @@ class LocalPaymentHandler(nodeParams: NodeParams) extends Actor with ActorLoggin } recover { case t => sender ! Status.Failure(t) } case CheckPayment(paymentHash) => - nodeParams.paymentsDb.findByPaymentHash(paymentHash) match { + nodeParams.db.payments.findByPaymentHash(paymentHash) match { case Some(_) => sender ! true case _ => sender ! false } @@ -92,7 +92,7 @@ class LocalPaymentHandler(nodeParams: NodeParams) extends Actor with ActorLoggin case _ => log.info(s"received payment for paymentHash=${htlc.paymentHash} amountMsat=${htlc.amountMsat}") // amount is correct or was not specified in the payment request - nodeParams.paymentsDb.addPayment(Payment(htlc.paymentHash, htlc.amountMsat, Platform.currentTime / 1000)) + nodeParams.db.payments.addPayment(Payment(htlc.paymentHash, htlc.amountMsat, Platform.currentTime / 1000)) sender ! CMD_FULFILL_HTLC(htlc.id, paymentPreimage, commit = true) context.system.eventStream.publish(PaymentReceived(MilliSatoshi(htlc.amountMsat), htlc.paymentHash, htlc.channelId)) context.become(run(hash2preimage - htlc.paymentHash)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala index 4c593daaf..e08a8e0e5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala @@ -136,7 +136,7 @@ class Router(nodeParams: NodeParams, watcher: ActorRef, initialized: Option[Prom } ) - val db = nodeParams.networkDb + val db = nodeParams.db.network { log.info("loading network announcements from db...") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala index 675dd3f32..615373a3f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala @@ -16,15 +16,10 @@ package fr.acinq.eclair -import java.io.File -import java.nio.file._ -import java.nio.file.attribute.BasicFileAttributes - import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.Block import fr.acinq.eclair.crypto.LocalKeyManager import org.scalatest.FunSuite - import scala.util.Try class StartupSpec extends FunSuite { @@ -38,31 +33,18 @@ class StartupSpec extends FunSuite { assert(baseUkraineAlias.getBytes.length === 27) // we add 2 UTF-8 chars, each is 3-bytes long -> total new length 33 bytes! - val goUkraineGo = threeBytesUTFChar+"BitcoinLightningNodeUkraine"+threeBytesUTFChar + val goUkraineGo = threeBytesUTFChar + "BitcoinLightningNodeUkraine" + threeBytesUTFChar assert(goUkraineGo.length === 29) assert(goUkraineGo.getBytes.length === 33) // too long for the alias, should be truncated val illegalAliasConf = ConfigFactory.parseString(s"node-alias = $goUkraineGo") val conf = illegalAliasConf.withFallback(ConfigFactory.parseResources("reference.conf").getConfig("eclair")) - val tempConfParentDir = new File("temp-test.conf") - val keyManager = new LocalKeyManager(seed = randomKey.toBin, chainHash = Block.TestnetGenesisBlock.hash) // try to create a NodeParams instance with a conf that contains an illegal alias - val nodeParamsAttempt = Try(NodeParams.makeNodeParams(tempConfParentDir, conf, keyManager, None)) + val nodeParamsAttempt = Try(NodeParams.makeNodeParams(conf, keyManager, None, TestConstants.inMemoryDb())) assert(nodeParamsAttempt.isFailure && nodeParamsAttempt.failed.get.getMessage.contains("alias, too long")) - - // destroy conf files after the test - Files.walkFileTree(tempConfParentDir.toPath, new SimpleFileVisitor[Path]() { - override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = { - Files.deleteIfExists(file) - FileVisitResult.CONTINUE - } - }) - - tempConfParentDir.listFiles.foreach(_.delete()) - tempConfParentDir.deleteOnExit() } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index db5523e79..4af457569 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -16,18 +16,18 @@ package fr.acinq.eclair -import java.sql.DriverManager +import java.sql.{Connection, DriverManager} import fr.acinq.bitcoin.Crypto.PrivateKey import fr.acinq.bitcoin.{Block, ByteVector32, Script} import fr.acinq.eclair.NodeParams.BITCOIND import fr.acinq.eclair.crypto.LocalKeyManager +import fr.acinq.eclair.db._ import fr.acinq.eclair.db.sqlite._ import fr.acinq.eclair.io.Peer import fr.acinq.eclair.router.RouterConf import fr.acinq.eclair.wire.{Color, NodeAddress} import scodec.bits.ByteVector - import scala.concurrent.duration._ /** @@ -38,12 +38,15 @@ object TestConstants { val pushMsat = 200000000L val feeratePerKw = 10000L + def sqliteInMemory() = DriverManager.getConnection("jdbc:sqlite::memory:") + + def inMemoryDb(connection: Connection = sqliteInMemory()): Databases = Databases.databaseByConnections(connection, connection, connection) + + object Alice { val seed = ByteVector32(ByteVector.fill(32)(1)) val keyManager = new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash) - def sqlite = DriverManager.getConnection("jdbc:sqlite::memory:") - // This is a function, and not a val! When called will return a new NodeParams def nodeParams = NodeParams( keyManager = keyManager, @@ -66,12 +69,7 @@ object TestConstants { feeProportionalMillionth = 10, reserveToFundingRatio = 0.01, // note: not used (overridden below) maxReserveToFundingRatio = 0.05, - channelsDb = new SqliteChannelsDb(sqlite), - peersDb = new SqlitePeersDb(sqlite), - networkDb = new SqliteNetworkDb(sqlite), - pendingRelayDb = new SqlitePendingRelayDb(sqlite), - paymentsDb = new SqlitePaymentsDb(sqlite), - auditDb = new SqliteAuditDb(sqlite), + db = inMemoryDb(sqliteInMemory), revocationTimeout = 20 seconds, pingInterval = 30 seconds, pingTimeout = 10 seconds, @@ -114,8 +112,6 @@ object TestConstants { val seed = ByteVector32(ByteVector.fill(32)(2)) val keyManager = new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash) - def sqlite = DriverManager.getConnection("jdbc:sqlite::memory:") - def nodeParams = NodeParams( keyManager = keyManager, alias = "bob", @@ -137,12 +133,7 @@ object TestConstants { feeProportionalMillionth = 10, reserveToFundingRatio = 0.01, // note: not used (overridden below) maxReserveToFundingRatio = 0.05, - channelsDb = new SqliteChannelsDb(sqlite), - peersDb = new SqlitePeersDb(sqlite), - networkDb = new SqliteNetworkDb(sqlite), - pendingRelayDb = new SqlitePendingRelayDb(sqlite), - paymentsDb = new SqlitePaymentsDb(sqlite), - auditDb = new SqliteAuditDb(sqlite), + db = inMemoryDb(sqliteInMemory), revocationTimeout = 20 seconds, pingInterval = 30 seconds, pingTimeout = 10 seconds, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index d6486a7a8..dddc43010 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -484,11 +484,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // depending on who starts signing first, there will be one or two commitments because both sides have changes assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.index === 1) assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.index === 2) - assert(alice.underlyingActor.nodeParams.channelsDb.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 0).size == 0) - assert(alice.underlyingActor.nodeParams.channelsDb.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 1).size == 2) - assert(alice.underlyingActor.nodeParams.channelsDb.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 2).size == 4) - assert(bob.underlyingActor.nodeParams.channelsDb.listHtlcInfos(bob.stateData.asInstanceOf[DATA_NORMAL].channelId, 0).size == 0) - assert(bob.underlyingActor.nodeParams.channelsDb.listHtlcInfos(bob.stateData.asInstanceOf[DATA_NORMAL].channelId, 1).size == 3) + assert(alice.underlyingActor.nodeParams.db.channels.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 0).size == 0) + assert(alice.underlyingActor.nodeParams.db.channels.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 1).size == 2) + assert(alice.underlyingActor.nodeParams.db.channels.listHtlcInfos(alice.stateData.asInstanceOf[DATA_NORMAL].channelId, 2).size == 4) + assert(bob.underlyingActor.nodeParams.db.channels.listHtlcInfos(bob.stateData.asInstanceOf[DATA_NORMAL].channelId, 0).size == 0) + assert(bob.underlyingActor.nodeParams.db.channels.listHtlcInfos(bob.stateData.asInstanceOf[DATA_NORMAL].channelId, 1).size == 3) } test("recv CMD_SIGN (htlcs with same pubkeyScript but different amounts)") { f => diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteChannelsDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteChannelsDbSpec.scala index 9f7185cfe..9e218c70d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteChannelsDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteChannelsDbSpec.scala @@ -50,10 +50,10 @@ class SqliteChannelsDbSpec extends FunSuite { intercept[SQLiteException](db.addOrUpdateHtlcInfo(channel.channelId, commitNumber, paymentHash1, cltvExpiry1)) // no related channel - assert(db.listChannels().toSet === Set.empty) + assert(db.listLocalChannels().toSet === Set.empty) db.addOrUpdateChannel(channel) db.addOrUpdateChannel(channel) - assert(db.listChannels() === List(channel)) + assert(db.listLocalChannels() === List(channel)) assert(db.listHtlcInfos(channel.channelId, commitNumber).toList == Nil) db.addOrUpdateHtlcInfo(channel.channelId, commitNumber, paymentHash1, cltvExpiry1) @@ -62,7 +62,7 @@ class SqliteChannelsDbSpec extends FunSuite { assert(db.listHtlcInfos(channel.channelId, 43).toList == Nil) db.removeChannel(channel.channelId) - assert(db.listChannels() === Nil) + assert(db.listLocalChannels() === Nil) assert(db.listHtlcInfos(channel.channelId, commitNumber).toList == Nil) } diff --git a/pom.xml b/pom.xml index 2d4b89a11..496aef988 100644 --- a/pom.xml +++ b/pom.xml @@ -217,6 +217,7 @@ ${project.build.directory} -Xmx1024m + -Dfile.encoding=UTF-8