1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-20 13:34:35 +01:00

Remove close() in db interfaces (#2303)

* Remove close() in db interfaces

It shouldn't be the responsibility of individual db classes to close
the underlying db connection because they typically share the same db
instance (postgres) or db files (sqlite). Closing should be handled in
the `Databases` level (which is already the case for postgres.

For sqlite, closing was only useful for mobile apps, which now use
lightning-kmp.

Also removed `DbFeeProvider`, which was only used by mobile apps.

* increase github ci build time 20min->30min
This commit is contained in:
Pierre-Marie Padiou 2022-06-08 10:39:21 +02:00 committed by GitHub
parent ecbec93dfe
commit e08353b243
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 10 additions and 408 deletions

View file

@ -10,7 +10,7 @@ jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 30
steps:
- uses: actions/checkout@v2

View file

@ -1,33 +0,0 @@
/*
* Copyright 2020 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.blockchain.fee
import fr.acinq.eclair.db.FeeratesDb
import scala.concurrent.{ExecutionContext, Future}
class DbFeeProvider(db: FeeratesDb, provider: FeeProvider)(implicit ec: ExecutionContext) extends FeeProvider {
/** This method retrieves feerates from the provider, and store results in the database */
override def getFeerates: Future[FeeratesPerKB] =
provider.getFeerates map { feerates =>
db.addOrUpdateFeerates(feerates)
feerates
}
}

View file

@ -18,15 +18,13 @@ package fr.acinq.eclair.db
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi}
import fr.acinq.eclair.{TimestampMilli, TimestampSecond}
import fr.acinq.eclair.TimestampMilli
import fr.acinq.eclair.channel._
import fr.acinq.eclair.db.AuditDb.{NetworkFee, Stats}
import fr.acinq.eclair.db.DbEventHandler.ChannelEvent
import fr.acinq.eclair.payment.{PathFindingExperimentMetrics, PaymentReceived, PaymentRelayed, PaymentSent}
import java.io.Closeable
trait AuditDb extends Closeable {
trait AuditDb {
def add(channelLifecycle: ChannelEvent): Unit

View file

@ -21,9 +21,7 @@ import fr.acinq.eclair.CltvExpiry
import fr.acinq.eclair.channel.PersistentChannelData
import fr.acinq.eclair.db.DbEventHandler.ChannelEvent
import java.io.Closeable
trait ChannelsDb extends Closeable {
trait ChannelsDb {
def addOrUpdateChannel(data: PersistentChannelData): Unit

View file

@ -132,11 +132,6 @@ case class DualNetworkDb(primary: NetworkDb, secondary: NetworkDb) extends Netwo
runAsync(secondary.isPruned(shortChannelId))
primary.isPruned(shortChannelId)
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
}
case class DualAuditDb(primary: AuditDb, secondary: AuditDb) extends AuditDb {
@ -212,11 +207,6 @@ case class DualAuditDb(primary: AuditDb, secondary: AuditDb) extends AuditDb {
runAsync(secondary.stats(from, to))
primary.stats(from, to)
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
}
case class DualChannelsDb(primary: ChannelsDb, secondary: ChannelsDb) extends ChannelsDb {
@ -257,11 +247,6 @@ case class DualChannelsDb(primary: ChannelsDb, secondary: ChannelsDb) extends Ch
runAsync(secondary.listHtlcInfos(channelId, commitmentNumber))
primary.listHtlcInfos(channelId, commitmentNumber)
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
}
case class DualPeersDb(primary: PeersDb, secondary: PeersDb) extends PeersDb {
@ -297,11 +282,6 @@ case class DualPeersDb(primary: PeersDb, secondary: PeersDb) extends PeersDb {
runAsync(secondary.getRelayFees(nodeId))
primary.getRelayFees(nodeId)
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
}
case class DualPaymentsDb(primary: PaymentsDb, secondary: PaymentsDb) extends PaymentsDb {
@ -313,11 +293,6 @@ case class DualPaymentsDb(primary: PaymentsDb, secondary: PaymentsDb) extends Pa
primary.listPaymentsOverview(limit)
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
override def addIncomingPayment(pr: Bolt11Invoice, preimage: ByteVector32, paymentType: String): Unit = {
runAsync(secondary.addIncomingPayment(pr, preimage, paymentType))
primary.addIncomingPayment(pr, preimage, paymentType)
@ -392,7 +367,6 @@ case class DualPaymentsDb(primary: PaymentsDb, secondary: PaymentsDb) extends Pa
runAsync(secondary.listOutgoingPayments(from, to))
primary.listOutgoingPayments(from, to)
}
}
case class DualPendingCommandsDb(primary: PendingCommandsDb, secondary: PendingCommandsDb) extends PendingCommandsDb {
@ -418,9 +392,4 @@ case class DualPendingCommandsDb(primary: PendingCommandsDb, secondary: PendingC
runAsync(secondary.listSettlementCommands())
primary.listSettlementCommands()
}
override def close(): Unit = {
runAsync(secondary.close())
primary.close()
}
}

View file

@ -1,34 +0,0 @@
/*
* Copyright 2020 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.db
import fr.acinq.eclair.blockchain.fee.FeeratesPerKB
import java.io.Closeable
/**
* This database stores the fee rates retrieved by a [[fr.acinq.eclair.blockchain.fee.FeeProvider]].
*/
trait FeeratesDb extends Closeable {
/** Insert or update the feerates into the feerates database. */
def addOrUpdateFeerates(feeratesPerKB: FeeratesPerKB): Unit
/** Return the (optional) feerates from the feerates database. */
def getFeerates(): Option[FeeratesPerKB]
}

View file

@ -22,10 +22,9 @@ import fr.acinq.eclair.ShortChannelId
import fr.acinq.eclair.router.Router.PublicChannel
import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement}
import java.io.Closeable
import scala.collection.immutable.SortedMap
trait NetworkDb extends Closeable {
trait NetworkDb {
def addNode(n: NodeAnnouncement): Unit

View file

@ -22,11 +22,10 @@ import fr.acinq.eclair.payment._
import fr.acinq.eclair.router.Router.{ChannelHop, Hop, NodeHop}
import fr.acinq.eclair.{MilliSatoshi, ShortChannelId, TimestampMilli}
import java.io.Closeable
import java.util.UUID
import scala.util.Try
trait PaymentsDb extends IncomingPaymentsDb with OutgoingPaymentsDb with PaymentsOverviewDb with Closeable
trait PaymentsDb extends IncomingPaymentsDb with OutgoingPaymentsDb with PaymentsOverviewDb
trait IncomingPaymentsDb {

View file

@ -20,9 +20,7 @@ import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.eclair.payment.relay.Relayer.RelayFees
import fr.acinq.eclair.wire.protocol.NodeAddress
import java.io.Closeable
trait PeersDb extends Closeable {
trait PeersDb {
def addOrUpdatePeer(nodeId: PublicKey, address: NodeAddress): Unit

View file

@ -22,8 +22,6 @@ import fr.acinq.bitcoin.scalacompat.ByteVector32
import fr.acinq.eclair.channel._
import fr.acinq.eclair.wire.protocol.{UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFulfillHtlc, UpdateMessage}
import java.io.Closeable
/**
* This database stores CMD_FULFILL_HTLC and CMD_FAIL_HTLC that we have received from downstream
* (either directly via UpdateFulfillHtlc or by extracting the value from the
@ -36,7 +34,7 @@ import java.io.Closeable
* to handle all corner cases.
*
*/
trait PendingCommandsDb extends Closeable {
trait PendingCommandsDb {
def addSettlementCommand(channelId: ByteVector32, cmd: HtlcSettlementCommand): Unit

View file

@ -474,7 +474,4 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging {
}
})
}
override def close(): Unit = ()
}

View file

@ -252,6 +252,4 @@ class PgChannelsDb(implicit ds: DataSource, lock: PgLock) extends ChannelsDb wit
}
}
}
override def close(): Unit = ()
}

View file

@ -267,6 +267,4 @@ class PgNetworkDb(implicit ds: DataSource) extends NetworkDb with Logging {
}
}
}
override def close(): Unit = ()
}

View file

@ -406,7 +406,4 @@ class PgPaymentsDb(implicit ds: DataSource, lock: PgLock) extends PaymentsDb wit
}
}
}
override def close(): Unit = ()
}

View file

@ -155,6 +155,4 @@ class PgPeersDb(implicit ds: DataSource, lock: PgLock) extends PeersDb with Logg
}
}
}
override def close(): Unit = ()
}

View file

@ -113,6 +113,4 @@ class PgPendingCommandsDb(implicit ds: DataSource, lock: PgLock) extends Pending
}
}
}
override def close(): Unit = ()
}

View file

@ -460,8 +460,4 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging {
}
})
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -188,7 +188,4 @@ class SqliteChannelsDb(val sqlite: Connection) extends ChannelsDb with Logging {
.toSeq
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -1,118 +0,0 @@
/*
* Copyright 2020 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.db.sqlite
import fr.acinq.bitcoin.scalacompat.Satoshi
import fr.acinq.eclair.TimestampMilli
import fr.acinq.eclair.blockchain.fee.{FeeratePerKB, FeeratesPerKB}
import fr.acinq.eclair.db.FeeratesDb
import grizzled.slf4j.Logging
import java.sql.{Connection, Statement}
object SqliteFeeratesDb {
val DB_NAME = "feerates"
val CURRENT_VERSION = 2
}
class SqliteFeeratesDb(sqlite: Connection) extends FeeratesDb with Logging {
import SqliteFeeratesDb._
import SqliteUtils.ExtendedResultSet._
import SqliteUtils._
using(sqlite.createStatement(), inTransaction = true) { statement =>
def migration12(statement: Statement): Unit = {
statement.executeUpdate("ALTER TABLE feerates_per_kb RENAME TO _feerates_per_kb_old")
statement.executeUpdate(
"""
|CREATE TABLE feerates_per_kb (
|rate_block_1 INTEGER NOT NULL, rate_blocks_2 INTEGER NOT NULL, rate_blocks_6 INTEGER NOT NULL, rate_blocks_12 INTEGER NOT NULL, rate_blocks_36 INTEGER NOT NULL, rate_blocks_72 INTEGER NOT NULL, rate_blocks_144 INTEGER NOT NULL, rate_blocks_1008 INTEGER NOT NULL,
|timestamp INTEGER NOT NULL)""".stripMargin)
statement.executeUpdate("INSERT INTO feerates_per_kb (rate_block_1, rate_blocks_2, rate_blocks_6, rate_blocks_12, rate_blocks_36, rate_blocks_72, rate_blocks_144, rate_blocks_1008, timestamp) SELECT rate_block_1, rate_blocks_2, rate_blocks_6, rate_blocks_12, rate_blocks_36, rate_blocks_72, rate_blocks_144, rate_blocks_144, timestamp FROM _feerates_per_kb_old")
statement.executeUpdate("DROP table _feerates_per_kb_old")
}
getVersion(statement, DB_NAME) match {
case None =>
// Create feerates table. Rates are in kb.
statement.executeUpdate(
"""
|CREATE TABLE feerates_per_kb (
|rate_block_1 INTEGER NOT NULL, rate_blocks_2 INTEGER NOT NULL, rate_blocks_6 INTEGER NOT NULL, rate_blocks_12 INTEGER NOT NULL, rate_blocks_36 INTEGER NOT NULL, rate_blocks_72 INTEGER NOT NULL, rate_blocks_144 INTEGER NOT NULL, rate_blocks_1008 INTEGER NOT NULL,
|timestamp INTEGER NOT NULL)""".stripMargin)
case Some(v@1) =>
logger.warn(s"migrating db $DB_NAME, found version=$v current=$CURRENT_VERSION")
migration12(statement)
case Some(CURRENT_VERSION) => () // table is up-to-date, nothing to do
case Some(unknownVersion) => throw new RuntimeException(s"Unknown version of DB $DB_NAME found, version=$unknownVersion")
}
setVersion(statement, DB_NAME, CURRENT_VERSION)
}
override def addOrUpdateFeerates(feeratesPerKB: FeeratesPerKB): Unit = {
using(sqlite.prepareStatement("UPDATE feerates_per_kb SET rate_block_1=?, rate_blocks_2=?, rate_blocks_6=?, rate_blocks_12=?, rate_blocks_36=?, rate_blocks_72=?, rate_blocks_144=?, rate_blocks_1008=?, timestamp=?")) { update =>
update.setLong(1, feeratesPerKB.block_1.toLong)
update.setLong(2, feeratesPerKB.blocks_2.toLong)
update.setLong(3, feeratesPerKB.blocks_6.toLong)
update.setLong(4, feeratesPerKB.blocks_12.toLong)
update.setLong(5, feeratesPerKB.blocks_36.toLong)
update.setLong(6, feeratesPerKB.blocks_72.toLong)
update.setLong(7, feeratesPerKB.blocks_144.toLong)
update.setLong(8, feeratesPerKB.blocks_1008.toLong)
update.setLong(9, TimestampMilli.now().toLong)
if (update.executeUpdate() == 0) {
using(sqlite.prepareStatement("INSERT INTO feerates_per_kb VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")) { insert =>
insert.setLong(1, feeratesPerKB.block_1.toLong)
insert.setLong(2, feeratesPerKB.blocks_2.toLong)
insert.setLong(3, feeratesPerKB.blocks_6.toLong)
insert.setLong(4, feeratesPerKB.blocks_12.toLong)
insert.setLong(5, feeratesPerKB.blocks_36.toLong)
insert.setLong(6, feeratesPerKB.blocks_72.toLong)
insert.setLong(7, feeratesPerKB.blocks_144.toLong)
insert.setLong(8, feeratesPerKB.blocks_1008.toLong)
insert.setLong(9, TimestampMilli.now().toLong)
insert.executeUpdate()
}
}
}
}
override def getFeerates(): Option[FeeratesPerKB] = {
using(sqlite.prepareStatement("SELECT rate_block_1, rate_blocks_2, rate_blocks_6, rate_blocks_12, rate_blocks_36, rate_blocks_72, rate_blocks_144, rate_blocks_1008 FROM feerates_per_kb")) { statement =>
statement.executeQuery()
.map { rs =>
FeeratesPerKB(
// NB: we don't bother storing this value in the DB, because it's unused on mobile.
mempoolMinFee = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_1008"))),
block_1 = FeeratePerKB(Satoshi(rs.getLong("rate_block_1"))),
blocks_2 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_2"))),
blocks_6 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_6"))),
blocks_12 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_12"))),
blocks_36 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_36"))),
blocks_72 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_72"))),
blocks_144 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_144"))),
blocks_1008 = FeeratePerKB(Satoshi(rs.getLong("rate_blocks_1008"))))
}
.headOption
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -176,7 +176,4 @@ class SqliteNetworkDb(val sqlite: Connection) extends NetworkDb with Logging {
statement.executeQuery().nonEmpty
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -396,10 +396,6 @@ class SqlitePaymentsDb(val sqlite: Connection) extends PaymentsDb with Logging {
}.toSeq
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}
object SqlitePaymentsDb {

View file

@ -128,8 +128,4 @@ class SqlitePeersDb(val sqlite: Connection) extends PeersDb with Logging {
)
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -88,7 +88,4 @@ class SqlitePendingCommandsDb(val sqlite: Connection) extends PendingCommandsDb
.toSeq
}
}
// used by mobile apps
override def close(): Unit = sqlite.close()
}

View file

@ -1,43 +0,0 @@
/*
* Copyright 2020 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.blockchain.fee
import akka.util.Timeout
import fr.acinq.bitcoin.scalacompat.SatoshiLong
import fr.acinq.eclair.TestDatabases
import fr.acinq.eclair.db.sqlite.SqliteFeeratesDb
import org.scalatest.funsuite.AnyFunSuite
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
class DbFeeProviderSpec extends AnyFunSuite {
val feerates1: FeeratesPerKB = FeeratesPerKB(FeeratePerKB(800 sat), FeeratePerKB(100 sat), FeeratePerKB(200 sat), FeeratePerKB(300 sat), FeeratePerKB(400 sat), FeeratePerKB(500 sat), FeeratePerKB(600 sat), FeeratePerKB(700 sat), FeeratePerKB(800 sat))
test("db fee provider saves feerates in database") {
val sqlite = TestDatabases.sqliteInMemory()
val db = new SqliteFeeratesDb(sqlite)
val provider = new DbFeeProvider(db, new ConstantFeeProvider(feerates1))
assert(db.getFeerates().isEmpty)
assert(Await.result(provider.getFeerates, Timeout(30 seconds).duration) == feerates1)
assert(db.getFeerates().get == feerates1)
}
}

View file

@ -1,94 +0,0 @@
/*
* Copyright 2020 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.db
import fr.acinq.bitcoin.scalacompat.SatoshiLong
import fr.acinq.eclair._
import fr.acinq.eclair.blockchain.fee.{FeeratePerKB, FeeratesPerKB}
import fr.acinq.eclair.db.pg.PgUtils.setVersion
import fr.acinq.eclair.db.sqlite.SqliteFeeratesDb
import fr.acinq.eclair.db.sqlite.SqliteUtils.{getVersion, using}
import org.scalatest.funsuite.AnyFunSuite
class SqliteFeeratesDbSpec extends AnyFunSuite {
val feerate: FeeratesPerKB = FeeratesPerKB(
mempoolMinFee = FeeratePerKB(10000 sat),
block_1 = FeeratePerKB(150000 sat),
blocks_2 = FeeratePerKB(120000 sat),
blocks_6 = FeeratePerKB(100000 sat),
blocks_12 = FeeratePerKB(90000 sat),
blocks_36 = FeeratePerKB(70000 sat),
blocks_72 = FeeratePerKB(50000 sat),
blocks_144 = FeeratePerKB(20000 sat),
blocks_1008 = FeeratePerKB(10000 sat))
test("init database 2 times in a row") {
val sqlite = TestDatabases.sqliteInMemory()
val db1 = new SqliteFeeratesDb(sqlite)
val db2 = new SqliteFeeratesDb(sqlite)
}
test("add/get feerates") {
val sqlite = TestDatabases.sqliteInMemory()
val db = new SqliteFeeratesDb(sqlite)
db.addOrUpdateFeerates(feerate)
assert(db.getFeerates().get == feerate)
}
test("migration v1 -> current") {
val sqlite = TestDatabases.sqliteInMemory()
using(sqlite.createStatement()) { statement =>
statement.executeUpdate(
"""
|CREATE TABLE IF NOT EXISTS feerates_per_kb (
|rate_block_1 INTEGER NOT NULL, rate_blocks_2 INTEGER NOT NULL, rate_blocks_6 INTEGER NOT NULL, rate_blocks_12 INTEGER NOT NULL, rate_blocks_36 INTEGER NOT NULL, rate_blocks_72 INTEGER NOT NULL, rate_blocks_144 INTEGER NOT NULL,
|timestamp INTEGER NOT NULL)""".stripMargin)
setVersion(statement, "feerates", 1)
}
using(sqlite.createStatement()) { statement =>
assert(getVersion(statement, "feerates").contains(1))
}
// Version 1 was missing the 1008 block target.
using(sqlite.prepareStatement("INSERT INTO feerates_per_kb VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) { statement =>
statement.setLong(1, feerate.block_1.toLong)
statement.setLong(2, feerate.blocks_2.toLong)
statement.setLong(3, feerate.blocks_6.toLong)
statement.setLong(4, feerate.blocks_12.toLong)
statement.setLong(5, feerate.blocks_36.toLong)
statement.setLong(6, feerate.blocks_72.toLong)
statement.setLong(7, feerate.blocks_144.toLong)
statement.setLong(8, TimestampMilli.now().toLong)
statement.executeUpdate()
}
val migratedDb = new SqliteFeeratesDb(sqlite)
using(sqlite.createStatement()) { statement =>
assert(getVersion(statement, "feerates").contains(SqliteFeeratesDb.CURRENT_VERSION))
}
// When migrating, we simply copy the estimate for blocks 144 to blocks 1008.
assert(migratedDb.getFeerates() == Some(feerate.copy(blocks_1008 = feerate.blocks_144, mempoolMinFee = feerate.blocks_144)))
migratedDb.addOrUpdateFeerates(feerate)
assert(migratedDb.getFeerates() == Some(feerate))
}
}

View file

@ -86,13 +86,13 @@ class SqliteUtilsSpec extends AnyFunSuite {
// first start : write to file
val db1 = Databases.sqlite(datadir, Some(jdbcUrlPath))
db1.channels.close()
db1.channels.sqlite.close()
assert(Files.readString(jdbcUrlPath.toPath).trim == "sqlite")
// 2nd start : no-op
val db2 = Databases.sqlite(datadir, Some(jdbcUrlPath))
db2.channels.close()
db2.channels.sqlite.close()
// we modify the file
Files.writeString(jdbcUrlPath.toPath, "postgres")