-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a fee provider saving feerates to database (#1450)
This provider will save the feerates retrieved by another provider to database. This feature can be used to retrieve the last used feerates when starting the node, which will save time. This can have a significant effect on nodes running with a slow connection (e.g. mobile devices). Note that this commit does not affect the current setup and does not actually create the database, the feature must be implemented separately. Fixes #1447
- Loading branch information
Showing
8 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/DbFeeProvider.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* 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 | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
eclair-core/src/main/scala/fr/acinq/eclair/db/FeeratesDb.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* 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 java.io.Closeable | ||
|
||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKB | ||
|
||
/** | ||
* 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] | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteFeeratesDb.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* 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 java.sql.Connection | ||
|
||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKB | ||
import fr.acinq.eclair.db.FeeratesDb | ||
|
||
|
||
class SqliteFeeratesDb(sqlite: Connection) extends FeeratesDb { | ||
|
||
import SqliteUtils._ | ||
|
||
val DB_NAME = "feerates" | ||
val CURRENT_VERSION = 1 | ||
|
||
using(sqlite.createStatement(), inTransaction = true) { statement => | ||
getVersion(statement, DB_NAME, CURRENT_VERSION) match { | ||
case CURRENT_VERSION => | ||
// Create feerates table. Rates are in kb. | ||
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) | ||
case unknownVersion => throw new RuntimeException(s"Unknown version of DB $DB_NAME found, version=$unknownVersion") | ||
} | ||
} | ||
|
||
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=?, timestamp=?")) { update => | ||
update.setLong(1, feeratesPerKB.block_1) | ||
update.setLong(2, feeratesPerKB.blocks_2) | ||
update.setLong(3, feeratesPerKB.blocks_6) | ||
update.setLong(4, feeratesPerKB.blocks_12) | ||
update.setLong(5, feeratesPerKB.blocks_36) | ||
update.setLong(6, feeratesPerKB.blocks_72) | ||
update.setLong(7, feeratesPerKB.blocks_144) | ||
update.setLong(8, System.currentTimeMillis()) | ||
if (update.executeUpdate() == 0) { | ||
using(sqlite.prepareStatement("INSERT INTO feerates_per_kb VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) { insert => | ||
insert.setLong(1, feeratesPerKB.block_1) | ||
insert.setLong(2, feeratesPerKB.blocks_2) | ||
insert.setLong(3, feeratesPerKB.blocks_6) | ||
insert.setLong(4, feeratesPerKB.blocks_12) | ||
insert.setLong(5, feeratesPerKB.blocks_36) | ||
insert.setLong(6, feeratesPerKB.blocks_72) | ||
insert.setLong(7, feeratesPerKB.blocks_144) | ||
insert.setLong(8, System.currentTimeMillis()) | ||
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 FROM feerates_per_kb")) { statement => | ||
val rs = statement.executeQuery() | ||
if (rs.next()) { | ||
Some(FeeratesPerKB( | ||
block_1 = rs.getLong("rate_block_1"), | ||
blocks_2 = rs.getLong("rate_blocks_2"), | ||
blocks_6 = rs.getLong("rate_blocks_6"), | ||
blocks_12 = rs.getLong("rate_blocks_12"), | ||
blocks_36 = rs.getLong("rate_blocks_36"), | ||
blocks_72 = rs.getLong("rate_blocks_72"), | ||
blocks_144 = rs.getLong("rate_blocks_144"))) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
// used by mobile apps | ||
override def close(): Unit = sqlite.close() | ||
} |
42 changes: 42 additions & 0 deletions
42
eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/DbFeeProviderSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* 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.eclair.TestConstants | ||
import fr.acinq.eclair.db.sqlite.SqliteFeeratesDb | ||
import org.scalatest.funsuite.AnyFunSuite | ||
|
||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.duration._ | ||
import scala.concurrent.{Await, Future} | ||
|
||
|
||
class DbFeeProviderSpec extends AnyFunSuite { | ||
|
||
val feerates1: FeeratesPerKB = FeeratesPerKB(100, 200, 300, 400, 500, 600, 700) | ||
|
||
test("db fee provider saves feerates in database") { | ||
val sqlite = TestConstants.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) | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteFeeratesDbSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* 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._ | ||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKB | ||
import fr.acinq.eclair.db.sqlite.SqliteFeeratesDb | ||
import org.scalatest.funsuite.AnyFunSuite | ||
|
||
class SqliteFeeratesDbSpec extends AnyFunSuite { | ||
|
||
test("init sqlite 2 times in a row") { | ||
val sqlite = TestConstants.sqliteInMemory() | ||
val db1 = new SqliteFeeratesDb(sqlite) | ||
val db2 = new SqliteFeeratesDb(sqlite) | ||
} | ||
|
||
test("add/get feerates") { | ||
val sqlite = TestConstants.sqliteInMemory() | ||
val db = new SqliteFeeratesDb(sqlite) | ||
val feerate = FeeratesPerKB( | ||
block_1 = 150000, | ||
blocks_2 = 120000, | ||
blocks_6 = 100000, | ||
blocks_12 = 90000, | ||
blocks_36 = 70000, | ||
blocks_72 = 50000, | ||
blocks_144 = 20000) | ||
|
||
db.addOrUpdateFeerates(feerate) | ||
assert(db.getFeerates().get == feerate) | ||
} | ||
} |