Skip to content

Commit ae3e44b

Browse files
authored
Remove legacy channel codecs and DB migrations (#3150)
* Remove legacy channel codecs We remove legacy channel codecs (versions earlier than v5). We also remove the corresponding DB migrations: if node operators try to upgrade from a version of eclair that is older than v0.13, we tell them to first run the v0.13 version to migrate their channel data. We regenerate serialization backwards-compatibility test vectors based on anchor outputs or taproot channel types. * Check channels DB version early We check the channels DB version before running any DB migration, to ensure that node operators can safely run the v0.13 release first. Otherwise we may have started migrating an unrelated table to a newer version that isn't included in the v0.13 release, which would thus fail at start-up. * Remove migration from `sqlite` to `postgres` We now expect users to directly use `postgres` if they expect their node to become large. The `sqlite` option should only be used for small nodes for individuals, where it is performant enough.
1 parent f029584 commit ae3e44b

File tree

100 files changed

+4124
-7993
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+4124
-7993
lines changed

docs/PostgreSQL.md

Lines changed: 33 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,34 @@
22

33
By default, Eclair stores its data on the machine's local file system (typically in `~/.eclair` directory) using SQLite.
44

5-
It also supports PostgreSQL version 10.6 and higher as a database backend.
5+
It also supports PostgreSQL version 10.6 and higher as a database backend.
66

77
To enable PostgreSQL support set the `driver` parameter to `postgres`:
88

9-
```
9+
```conf
1010
eclair.db.driver = postgres
1111
```
1212

1313
### Connection settings
1414

1515
To configure the connection settings use the `database`, `host`, `port` `username` and `password` parameters:
1616

17-
```
17+
```conf
1818
eclair.db.postgres.database = "mydb"
1919
eclair.db.postgres.host = "127.0.0.1" # Default: "localhost"
2020
eclair.db.postgres.port = 12345 # Default: 5432
2121
eclair.db.postgres.username = "myuser"
2222
eclair.db.postgres.password = "mypassword"
2323
```
2424

25-
Eclair uses Hikari connection pool (https://github.com/brettwooldridge/HikariCP) which has a lot of configuration
26-
parameters. Some of them can be set in Eclair config file. The most important is `pool.max-size`, it defines the maximum
27-
allowed number of simultaneous connections to the database.
25+
Eclair uses [Hikari connection pool](https://github.com/brettwooldridge/HikariCP) which has a lot of configuration parameters.
26+
Some of them can be set in Eclair config file.
27+
The most important is `pool.max-size`, it defines the maximum allowed number of simultaneous connections to the database.
2828

29-
A good rule of thumb is to set `pool.max-size` to the CPU core count times 2.
30-
See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing for better estimation.
29+
A good rule of thumb is to set `pool.max-size` to the CPU core count times 2.
30+
See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing for better estimation.
3131

32-
```
32+
```conf
3333
eclair.db.postgres.pool {
3434
max-size = 8 # Default: 10
3535
connection-timeout = 10 seconds # Default: 30 seconds
@@ -39,29 +39,28 @@ eclair.db.postgres.pool {
3939
```
4040

4141
### Locking settings
42-
43-
Running multiple Eclair processes connected to the same database can lead to data corruption and loss of funds.
44-
That's why Eclair supports database locking mechanisms to prevent multiple Eclair instances from accessing one database together.
42+
43+
Running multiple Eclair processes connected to the same database can lead to data corruption and loss of funds.
44+
That's why Eclair supports database locking mechanisms to prevent multiple Eclair instances from accessing one database together.
4545

4646
Use `postgres.lock-type` parameter to set the locking schemes.
4747

48-
Lock type | Description
49-
---|---
50-
`lease` | At the beginning, Eclair acquires a lease for the database that expires after some time. Then it constantly extends the lease. On each lease extension and each database transaction, Eclair checks if the lease belongs to the Eclair instance. If it doesn't, Eclair assumes that the database was updated by another Eclair process and terminates. Note that this is just a safeguard feature for Eclair rather than a bulletproof database-wide lock, because third-party applications still have the ability to access the database without honoring this locking scheme.
51-
`none` | No locking at all. Useful for tests. DO NOT USE ON MAINNET!
48+
Lock type | Description
49+
-----------|----------------
50+
`lease` | At the beginning, Eclair acquires a lease for the database that expires after some time. Then it constantly extends the lease. On each lease extension and each database transaction, Eclair checks if the lease belongs to the Eclair instance. If it doesn't, Eclair assumes that the database was updated by another Eclair process and terminates. Note that this is just a safeguard feature for Eclair rather than a bulletproof database-wide lock, because third-party applications still have the ability to access the database without honoring this locking scheme.
51+
`none` | No locking at all. Useful for tests. DO NOT USE ON MAINNET!
5252

53-
```
53+
```conf
5454
eclair.db.postgres.lock-type = "none" // Default: "lease"
5555
```
5656

5757
#### Database Lease Settings
5858

5959
There are two main configuration parameters for the lease locking scheme: `lease.interval` and `lease.renew-interval`.
6060
`lease.interval` defines lease validity time. During the lease time no other node can acquire the lock, except the lease holder.
61-
After that time the lease is assumed expired, any node can acquire the lease. So that only one node can update the database
62-
at a time. Eclair extends the lease every `lease.renew-interval` until terminated.
61+
After that time the lease is assumed expired, any node can acquire the lease. So that only one node can update the database at a time. Eclair extends the lease every `lease.renew-interval` until terminated.
6362

64-
```
63+
```conf
6564
eclair.db.postgres.lease {
6665
interval = 30 seconds // Default: 5 minutes
6766
renew-interval = 10 seconds // Default: 1 minute
@@ -70,75 +69,38 @@ eclair.db.postgres.lease {
7069

7170
### Backups and replication
7271

73-
The PostgreSQL driver doesn't support Eclair's built-in online backups. Instead, you should use the tools provided
74-
by PostgreSQL.
72+
The PostgreSQL driver doesn't support Eclair's built-in online backups. Instead, you should use the tools provided by PostgreSQL.
7573

7674
#### Backup/Restore
7775

78-
For nodes with infrequent channel updates its easier to use `pg_dump` to perform the task.
76+
For nodes with infrequent channel updates its easier to use `pg_dump` to perform the task.
7977

80-
It's important to stop the node to prevent any channel updates while a backup/restore operation is in progress. It makes
81-
sense to back up the database after each channel update, to prevent restoring an outdated channel's state and consequently
82-
losing the funds associated with that channel.
78+
It's important to stop the node to prevent any channel updates while a backup/restore operation is in progress. It makes sense to back up the database after each channel update, to prevent restoring an outdated channel's state and consequently losing the funds associated with that channel.
8379

8480
For more information about backup refer to the official PostgreSQL documentation: https://www.postgresql.org/docs/current/backup.html
8581

8682
#### Replication
8783

8884
For busier nodes it isn't practical to use `pg_dump`. Fortunately, PostgreSQL provides built-in database replication which makes the backup/restore process more seamless.
8985

90-
To set up database replication you need to create a main database, that accepts all changes from the node, and a replica database.
91-
Once replication is configured, the main database will automatically send all the changes to the replica.
86+
To set up database replication you need to create a main database, that accepts all changes from the node, and a replica database.
87+
Once replication is configured, the main database will automatically send all the changes to the replica.
9288
In case of failure of the main database, the node can be simply reconfigured to use the replica instead of the main database.
9389

94-
PostgreSQL supports [different types of replication](https://www.postgresql.org/docs/current/different-replication-solutions.html).
95-
The most suitable type for an Eclair node is [synchronous streaming replication](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION),
96-
because it provides a very important feature, that helps keep the replicated channel's state up to date:
90+
PostgreSQL supports [different types of replication](https://www.postgresql.org/docs/current/different-replication-solutions.html).
91+
The most suitable type for an Eclair node is [synchronous streaming replication](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION), because it provides a very important feature, that helps keep the replicated channel's state up to date:
9792

9893
> When requesting synchronous replication, each commit of a write transaction will wait until confirmation is received that the commit has been written to the write-ahead log on disk of both the primary and standby server.
9994
100-
Follow the official PostgreSQL high availability documentation for the instructions to set up synchronous streaming replication: https://www.postgresql.org/docs/current/high-availability.html
95+
Follow the official PostgreSQL [high availability documentation](https://www.postgresql.org/docs/current/high-availability.html) for the instructions to set up synchronous streaming replication.
10196

10297
### Safeguard to prevent accidental loss of funds due to database misconfiguration
10398

10499
Using Eclair with an outdated version of the database or a database created with another seed might lead to loss of funds.
105100

106-
Every time Eclair starts, it checks if the Postgres database connection settings have changed since the last start.
107-
If in fact the settings have changed, Eclair stops immediately to prevent potentially dangerous
108-
but accidental configuration changes to come into effect.
109-
110-
Eclair stores the latest database settings in the `${data-dir}/last_jdbcurl` file, and compares its contents with the database settings from the config file.
111-
112-
The node operator can force Eclair to accept new database
113-
connection settings by removing the `last_jdbcurl` file.
114-
115-
### Migrating from Sqlite to Postgres
116-
117-
Eclair supports migrating your existing node from Sqlite to Postgres. Note that the opposite (from Postgres to Sqlite) is not supported.
118-
119-
:warning: Once you have migrated from Sqlite to Postgres there is no going back!
120-
121-
To migrate from Sqlite to Postgres, follow these steps:
122-
1. Stop Eclair
123-
2. Edit `eclair.conf`
124-
1. Set `eclair.db.postgres.*` as explained in the section [Connection Settings](#connection-settings).
125-
2. Set `eclair.db.driver=dual-sqlite-primary`. This will make Eclair use both databases backends. All calls to sqlite will be replicated in postgres.
126-
3. Set `eclair.db.dual.migrate-on-restart=true`. This will make Eclair migrate the data from Sqlite to Postgres at startup.
127-
4. Set `eclair.db.dual.compare-on-restart=true`. This will make Eclair compare Sqlite and Postgres at startup. The result of the comparison is displayed in the logs.
128-
3. Delete the file `~/.eclair/last_jdbcurl`. The purpose of this file is to prevent accidental change in the database backend.
129-
4. Start Eclair. You should see in the logs:
130-
1. `migrating all tables...`
131-
2. `migration complete`
132-
3. `comparing all tables...`
133-
4. `comparison complete identical=true` (NB: if `identical=false`, contact support)
134-
5. Eclair should then finish startup and operate normally. Data has been migrated to Postgres, and Sqlite/Postgres will be maintained in sync going forward.
135-
6. Edit `eclair.conf` and set `eclair.db.dual.migrate-on-restart=false` but do not restart Eclair yet.
136-
7. We recommend that you leave Eclair in dual db mode for a while, to make sure that you don't have issues with your new Postgres database. This a good time to set up [Backups and replication](#backups-and-replication).
137-
8. After some time has passed, restart Eclair. You should see in the logs:
138-
1. `comparing all tables...`
139-
2. `comparison complete identical=true` (NB: if `identical=false`, contact support)
140-
9. At this point we have confidence that the Postgres backend works normally, and we are ready to drop Sqlite for good.
141-
10. Edit `eclair.conf`
142-
1. Set `eclair.db.driver=postgres`
143-
2. Set `eclair.db.dual.compare-on-restart=false`
144-
11. Restart Eclair. From this moment, you cannot go back to Sqlite! If you try to do so, Eclair will refuse to start.
101+
Every time Eclair starts, it checks if the Postgres database connection settings have changed since the last start.
102+
If in fact the settings have changed, Eclair stops immediately to prevent potentially dangerous but accidental configuration changes to come into effect.
103+
104+
Eclair stores the latest database settings in the `${data-dir}/last_jdbcurl` file, and compares its contents with the database settings from the config file.
105+
106+
The node operator can force Eclair to accept new database connection settings by removing the `last_jdbcurl` file.

docs/release-notes/eclair-vnext.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
<insert changes>
88

9+
### Remove support for legacy channel codecs
10+
11+
We remove the code used to deserialize channel data from versions of eclair prior to v0.13.
12+
Node operators running a version of `eclair` older than v0.13 must first upgrade to v0.13 to migrate their channel data, and then upgrade to the latest version.
13+
914
### Update minimal version of Bitcoin Core
1015

1116
With this release, eclair requires using Bitcoin Core 29.1.

eclair-core/src/main/resources/reference.conf

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ eclair {
550550
}
551551

552552
db {
553-
driver = "sqlite" // sqlite, postgres, dual-sqlite-primary, dual-postgres-primary
553+
driver = "sqlite" // sqlite, postgres
554554
postgres {
555555
database = "eclair"
556556
host = "localhost"
@@ -592,10 +592,6 @@ eclair {
592592
}
593593
}
594594
}
595-
dual {
596-
migrate-on-restart = false // migrate sqlite -> postgres on restart (only applies if sqlite is primary)
597-
compare-on-restart = false // compare sqlite and postgres dbs on restart (only applies if sqlite is primary)
598-
}
599595
// During normal channel operation, we need to store information about past HTLCs to be able to punish our peer if
600596
// they publish a revoked commitment. Once a channel closes or a splice transaction confirms, we can clean up past
601597
// data (which reduces the size of our DB). Since there may be millions of rows to delete and we don't want to slow

eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import akka.actor.{ActorSystem, CoordinatedShutdown}
2121
import com.typesafe.config.Config
2222
import com.zaxxer.hikari.{HikariConfig, HikariDataSource}
2323
import fr.acinq.eclair.TimestampMilli
24-
import fr.acinq.eclair.db.migration.{CompareDb, MigrateDb}
2524
import fr.acinq.eclair.db.pg.PgUtils.PgLock.LockFailureHandler
2625
import fr.acinq.eclair.db.pg.PgUtils._
2726
import fr.acinq.eclair.db.pg._
@@ -80,6 +79,8 @@ object Databases extends Logging {
8079
object SqliteDatabases {
8180
def apply(auditJdbc: Connection, networkJdbc: Connection, eclairJdbc: Connection, jdbcUrlFile_opt: Option[File]): SqliteDatabases = {
8281
jdbcUrlFile_opt.foreach(checkIfDatabaseUrlIsUnchanged("sqlite", _))
82+
// We check whether the node operator needs to run an intermediate eclair version first.
83+
using(eclairJdbc.createStatement(), inTransaction = true) { statement => checkChannelsDbVersion(statement, SqliteChannelsDb.DB_NAME, minimum = 7) }
8384
SqliteDatabases(
8485
network = new SqliteNetworkDb(networkJdbc),
8586
liquidity = new SqliteLiquidityDb(eclairJdbc),
@@ -154,6 +155,11 @@ object Databases extends Logging {
154155
}
155156
}
156157

158+
// We check whether the node operator needs to run an intermediate eclair version first.
159+
PgUtils.inTransaction { connection =>
160+
using(connection.createStatement()) { statement => checkChannelsDbVersion(statement, PgChannelsDb.DB_NAME, minimum = 11) }
161+
}
162+
157163
val databases = PostgresDatabases(
158164
network = new PgNetworkDb,
159165
liquidity = new PgLiquidityDb,
@@ -281,21 +287,6 @@ object Databases extends Logging {
281287
dbConfig.getString("driver") match {
282288
case "sqlite" => Databases.sqlite(chaindir, jdbcUrlFile_opt = Some(jdbcUrlFile))
283289
case "postgres" => Databases.postgres(dbConfig, instanceId, chaindir, jdbcUrlFile_opt = Some(jdbcUrlFile))
284-
case dual@("dual-sqlite-primary" | "dual-postgres-primary") =>
285-
logger.info(s"using $dual database mode")
286-
val sqlite = Databases.sqlite(chaindir, jdbcUrlFile_opt = None)
287-
val postgres = Databases.postgres(dbConfig, instanceId, chaindir, jdbcUrlFile_opt = None)
288-
val (primary, secondary) = if (dual == "dual-sqlite-primary") (sqlite, postgres) else (postgres, sqlite)
289-
val dualDb = DualDatabases(primary, secondary)
290-
if (primary == sqlite) {
291-
if (dbConfig.getBoolean("dual.migrate-on-restart")) {
292-
MigrateDb.migrateAll(dualDb)
293-
}
294-
if (dbConfig.getBoolean("dual.compare-on-restart")) {
295-
CompareDb.compareAll(dualDb)
296-
}
297-
}
298-
dualDb
299290
case driver => throw new RuntimeException(s"unknown database driver `$driver`")
300291
}
301292
}

0 commit comments

Comments
 (0)