Merge channels and payments database
There is now only one database file, phoenix.db. This makes database backup easier. Legacy channels closing parts have been removed (we use a dedicated table to store closings). The tables storing lightning outgoing payments have been renamed for consistency by addingd a "lightning" prefix. The related kotlin classes have been renamed as well.
This commit is contained in:
parent
9d984591bc
commit
64775d2fd5
@ -107,13 +107,9 @@ tasks.withType<JavaExec> {
|
||||
|
||||
sqldelight {
|
||||
databases {
|
||||
create("ChannelsDatabase") {
|
||||
create("PhoenixDatabase") {
|
||||
packageName.set("fr.acinq.phoenix.db")
|
||||
srcDirs.from("src/commonMain/sqldelight/channelsdb")
|
||||
}
|
||||
create("PaymentsDatabase") {
|
||||
packageName.set("fr.acinq.phoenix.db")
|
||||
srcDirs.from("src/commonMain/sqldelight/paymentsdb")
|
||||
srcDirs.from("src/commonMain/sqldelight/phoenixdb")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,3 @@ import okio.Path
|
||||
expect val homeDirectory: Path
|
||||
|
||||
expect fun createAppDbDriver(dir: Path): SqlDriver
|
||||
expect fun createPaymentsDbDriver(dir: Path): SqlDriver
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.acinq.lightning.bin
|
||||
|
||||
import app.cash.sqldelight.EnumColumnAdapter
|
||||
import co.touchlab.kermit.CommonWriter
|
||||
import co.touchlab.kermit.Severity
|
||||
import co.touchlab.kermit.StaticConfig
|
||||
@ -27,6 +28,7 @@ import fr.acinq.lightning.bin.conf.getOrGenerateSeed
|
||||
import fr.acinq.lightning.bin.conf.readConfFile
|
||||
import fr.acinq.lightning.bin.db.SqliteChannelsDb
|
||||
import fr.acinq.lightning.bin.db.SqlitePaymentsDb
|
||||
import fr.acinq.lightning.bin.db.payments.LightningOutgoingQueries
|
||||
import fr.acinq.lightning.bin.json.ApiType
|
||||
import fr.acinq.lightning.bin.logs.FileLogWriter
|
||||
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
|
||||
@ -44,6 +46,7 @@ import fr.acinq.lightning.utils.Connection
|
||||
import fr.acinq.lightning.utils.ServerAddress
|
||||
import fr.acinq.lightning.utils.msat
|
||||
import fr.acinq.lightning.utils.sat
|
||||
import fr.acinq.phoenix.db.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.cio.*
|
||||
@ -210,14 +213,34 @@ class Phoenixd : CliktCommand() {
|
||||
)
|
||||
echo(cyan("nodeid: ${nodeParams.nodeId}"))
|
||||
|
||||
val driver = createAppDbDriver(datadir)
|
||||
val database = PhoenixDatabase(
|
||||
driver = driver,
|
||||
lightning_outgoing_payment_partsAdapter = Lightning_outgoing_payment_parts.Adapter(
|
||||
part_routeAdapter = LightningOutgoingQueries.hopDescAdapter,
|
||||
part_status_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
lightning_outgoing_paymentsAdapter = Lightning_outgoing_payments.Adapter(
|
||||
status_typeAdapter = EnumColumnAdapter(),
|
||||
details_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
incoming_paymentsAdapter = Incoming_payments.Adapter(
|
||||
origin_typeAdapter = EnumColumnAdapter(),
|
||||
received_with_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
channel_close_outgoing_paymentsAdapter = Channel_close_outgoing_payments.Adapter(
|
||||
closing_info_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
inbound_liquidity_outgoing_paymentsAdapter = Inbound_liquidity_outgoing_payments.Adapter(
|
||||
lease_typeAdapter = EnumColumnAdapter()
|
||||
)
|
||||
)
|
||||
|
||||
val electrum = ElectrumClient(scope, loggerFactory)
|
||||
val paymentsDb = SqlitePaymentsDb(loggerFactory, createPaymentsDbDriver(datadir))
|
||||
val peer = Peer(
|
||||
nodeParams = nodeParams, walletParams = lsp.walletParams, watcher = ElectrumWatcher(electrum, scope, loggerFactory), db = object : Databases {
|
||||
override val channels: ChannelsDb
|
||||
get() = SqliteChannelsDb(createAppDbDriver(datadir))
|
||||
override val payments: PaymentsDb
|
||||
get() = paymentsDb
|
||||
override val channels: ChannelsDb get() = SqliteChannelsDb(driver, database)
|
||||
override val payments: PaymentsDb get() = SqlitePaymentsDb(database)
|
||||
}, socketBuilder = TcpSocket.Builder(), scope
|
||||
)
|
||||
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* 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.lightning.bin.db
|
||||
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
@ -6,14 +22,13 @@ import fr.acinq.lightning.CltvExpiry
|
||||
import fr.acinq.lightning.channel.states.PersistedChannelState
|
||||
import fr.acinq.lightning.db.ChannelsDb
|
||||
import fr.acinq.lightning.serialization.Serialization
|
||||
import fr.acinq.phoenix.db.ChannelsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class SqliteChannelsDb(private val driver: SqlDriver) : ChannelsDb {
|
||||
internal class SqliteChannelsDb(val driver: SqlDriver, val database: PhoenixDatabase) : ChannelsDb {
|
||||
|
||||
private val database = ChannelsDatabase(driver)
|
||||
private val queries = database.channelsDatabaseQueries
|
||||
private val queries = database.channelsQueries
|
||||
|
||||
override suspend fun addOrUpdateChannel(state: PersistedChannelState) {
|
||||
val channelId = state.channelId.toByteArray()
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package fr.acinq.lightning.bin.db
|
||||
|
||||
import app.cash.sqldelight.EnumColumnAdapter
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import fr.acinq.bitcoin.ByteVector32
|
||||
import fr.acinq.bitcoin.Crypto
|
||||
import fr.acinq.bitcoin.TxId
|
||||
@ -27,8 +25,6 @@ import fr.acinq.lightning.bin.db.payments.LinkTxToPaymentQueries
|
||||
import fr.acinq.lightning.bin.db.payments.PaymentsMetadataQueries
|
||||
import fr.acinq.lightning.channel.ChannelException
|
||||
import fr.acinq.lightning.db.*
|
||||
import fr.acinq.lightning.logging.LoggerFactory
|
||||
import fr.acinq.lightning.logging.info
|
||||
import fr.acinq.lightning.payment.FinalFailure
|
||||
import fr.acinq.lightning.utils.*
|
||||
import fr.acinq.lightning.wire.FailureMessage
|
||||
@ -36,40 +32,10 @@ import fr.acinq.phoenix.db.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SqlitePaymentsDb(
|
||||
loggerFactory: LoggerFactory,
|
||||
private val driver: SqlDriver,
|
||||
) : PaymentsDb {
|
||||
|
||||
private val log = loggerFactory.newLogger(this::class)
|
||||
|
||||
private val database = PaymentsDatabase(
|
||||
driver = driver,
|
||||
outgoing_payment_partsAdapter = Outgoing_payment_parts.Adapter(
|
||||
part_routeAdapter = OutgoingQueries.hopDescAdapter,
|
||||
part_status_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
outgoing_paymentsAdapter = Outgoing_payments.Adapter(
|
||||
status_typeAdapter = EnumColumnAdapter(),
|
||||
details_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
incoming_paymentsAdapter = Incoming_payments.Adapter(
|
||||
origin_typeAdapter = EnumColumnAdapter(),
|
||||
received_with_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
outgoing_payment_closing_tx_partsAdapter = Outgoing_payment_closing_tx_parts.Adapter(
|
||||
part_closing_info_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
channel_close_outgoing_paymentsAdapter = Channel_close_outgoing_payments.Adapter(
|
||||
closing_info_typeAdapter = EnumColumnAdapter()
|
||||
),
|
||||
inbound_liquidity_outgoing_paymentsAdapter = Inbound_liquidity_outgoing_payments.Adapter(
|
||||
lease_typeAdapter = EnumColumnAdapter()
|
||||
)
|
||||
)
|
||||
class SqlitePaymentsDb(val database: PhoenixDatabase) : PaymentsDb {
|
||||
|
||||
private val inQueries = IncomingQueries(database)
|
||||
private val outQueries = OutgoingQueries(database)
|
||||
private val lightningOutgoingQueries = LightningOutgoingQueries(database)
|
||||
private val spliceOutQueries = SpliceOutgoingQueries(database)
|
||||
private val channelCloseQueries = ChannelCloseOutgoingQueries(database)
|
||||
private val cpfpQueries = SpliceCpfpOutgoingQueries(database)
|
||||
@ -82,7 +48,7 @@ class SqlitePaymentsDb(
|
||||
parts: List<LightningOutgoingPayment.Part>
|
||||
) {
|
||||
withContext(Dispatchers.Default) {
|
||||
outQueries.addLightningParts(parentId, parts)
|
||||
lightningOutgoingQueries.addLightningParts(parentId, parts)
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +59,7 @@ class SqlitePaymentsDb(
|
||||
database.transaction {
|
||||
when (outgoingPayment) {
|
||||
is LightningOutgoingPayment -> {
|
||||
outQueries.addLightningOutgoingPayment(outgoingPayment)
|
||||
lightningOutgoingQueries.addLightningOutgoingPayment(outgoingPayment)
|
||||
}
|
||||
is SpliceOutgoingPayment -> {
|
||||
spliceOutQueries.addSpliceOutgoingPayment(outgoingPayment)
|
||||
@ -128,7 +94,7 @@ class SqlitePaymentsDb(
|
||||
completedAt: Long
|
||||
) {
|
||||
withContext(Dispatchers.Default) {
|
||||
outQueries.completePayment(id, LightningOutgoingPayment.Status.Completed.Succeeded.OffChain(preimage, completedAt))
|
||||
lightningOutgoingQueries.completePayment(id, LightningOutgoingPayment.Status.Completed.Succeeded.OffChain(preimage, completedAt))
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +104,7 @@ class SqlitePaymentsDb(
|
||||
completedAt: Long
|
||||
) {
|
||||
withContext(Dispatchers.Default) {
|
||||
outQueries.completePayment(id, LightningOutgoingPayment.Status.Completed.Failed(finalFailure, completedAt))
|
||||
lightningOutgoingQueries.completePayment(id, LightningOutgoingPayment.Status.Completed.Failed(finalFailure, completedAt))
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +114,7 @@ class SqlitePaymentsDb(
|
||||
completedAt: Long
|
||||
) {
|
||||
withContext(Dispatchers.Default) {
|
||||
outQueries.updateLightningPart(partId, preimage, completedAt)
|
||||
lightningOutgoingQueries.updateLightningPart(partId, preimage, completedAt)
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,16 +124,16 @@ class SqlitePaymentsDb(
|
||||
completedAt: Long
|
||||
) {
|
||||
withContext(Dispatchers.Default) {
|
||||
outQueries.updateLightningPart(partId, failure, completedAt)
|
||||
lightningOutgoingQueries.updateLightningPart(partId, failure, completedAt)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getLightningOutgoingPayment(id: UUID): LightningOutgoingPayment? = withContext(Dispatchers.Default) {
|
||||
outQueries.getPayment(id)
|
||||
lightningOutgoingQueries.getPayment(id)
|
||||
}
|
||||
|
||||
override suspend fun getLightningOutgoingPaymentFromPartId(partId: UUID): LightningOutgoingPayment? = withContext(Dispatchers.Default) {
|
||||
outQueries.getPaymentFromPartId(partId)
|
||||
lightningOutgoingQueries.getPaymentFromPartId(partId)
|
||||
}
|
||||
|
||||
// ---- list outgoing
|
||||
@ -175,7 +141,7 @@ class SqlitePaymentsDb(
|
||||
override suspend fun listLightningOutgoingPayments(
|
||||
paymentHash: ByteVector32
|
||||
): List<LightningOutgoingPayment> = withContext(Dispatchers.Default) {
|
||||
outQueries.listLightningOutgoingPayments(paymentHash)
|
||||
lightningOutgoingQueries.listLightningOutgoingPayments(paymentHash)
|
||||
}
|
||||
|
||||
// ---- incoming payments
|
||||
|
@ -21,9 +21,9 @@ import fr.acinq.lightning.db.ChannelCloseOutgoingPayment
|
||||
import fr.acinq.lightning.utils.UUID
|
||||
import fr.acinq.lightning.utils.sat
|
||||
import fr.acinq.lightning.utils.toByteVector32
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
|
||||
class ChannelCloseOutgoingQueries(val database: PaymentsDatabase) {
|
||||
class ChannelCloseOutgoingQueries(val database: PhoenixDatabase) {
|
||||
private val channelCloseQueries = database.channelCloseOutgoingPaymentsQueries
|
||||
|
||||
fun getChannelCloseOutgoingPayment(id: UUID): ChannelCloseOutgoingPayment? {
|
||||
@ -74,7 +74,7 @@ class ChannelCloseOutgoingQueries(val database: PaymentsDatabase) {
|
||||
confirmed_at: Long?,
|
||||
locked_at: Long?,
|
||||
channel_id: ByteArray,
|
||||
closing_info_type: OutgoingPartClosingInfoTypeVersion,
|
||||
closing_info_type: ClosingInfoTypeVersion,
|
||||
closing_info_blob: ByteArray
|
||||
): ChannelCloseOutgoingPayment {
|
||||
return ChannelCloseOutgoingPayment(
|
||||
@ -88,7 +88,7 @@ class ChannelCloseOutgoingQueries(val database: PaymentsDatabase) {
|
||||
confirmedAt = confirmed_at,
|
||||
lockedAt = locked_at,
|
||||
channelId = channel_id.toByteVector32(),
|
||||
closingType = OutgoingPartClosingInfoData.deserialize(closing_info_type, closing_info_blob),
|
||||
closingType = ClosingInfoData.deserialize(closing_info_type, closing_info_blob),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -25,24 +25,24 @@ import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
enum class OutgoingPartClosingInfoTypeVersion {
|
||||
enum class ClosingInfoTypeVersion {
|
||||
// basic type, containing only a [ChannelClosingType] field
|
||||
CLOSING_INFO_V0,
|
||||
}
|
||||
|
||||
sealed class OutgoingPartClosingInfoData {
|
||||
sealed class ClosingInfoData {
|
||||
|
||||
@Serializable
|
||||
data class V0(val closingType: ChannelClosingType)
|
||||
|
||||
companion object {
|
||||
fun deserialize(typeVersion: OutgoingPartClosingInfoTypeVersion, blob: ByteArray): ChannelClosingType = DbTypesHelper.decodeBlob(blob) { json, format ->
|
||||
fun deserialize(typeVersion: ClosingInfoTypeVersion, blob: ByteArray): ChannelClosingType = DbTypesHelper.decodeBlob(blob) { json, format ->
|
||||
when (typeVersion) {
|
||||
OutgoingPartClosingInfoTypeVersion.CLOSING_INFO_V0 -> format.decodeFromString<V0>(json).closingType
|
||||
ClosingInfoTypeVersion.CLOSING_INFO_V0 -> format.decodeFromString<V0>(json).closingType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ChannelCloseOutgoingPayment.mapClosingTypeToDb() = OutgoingPartClosingInfoTypeVersion.CLOSING_INFO_V0 to
|
||||
Json.encodeToString(OutgoingPartClosingInfoData.V0(this.closingType)).toByteArray(Charsets.UTF_8)
|
||||
fun ChannelCloseOutgoingPayment.mapClosingTypeToDb() = ClosingInfoTypeVersion.CLOSING_INFO_V0 to
|
||||
Json.encodeToString(ClosingInfoData.V0(this.closingType)).toByteArray(Charsets.UTF_8)
|
@ -21,10 +21,10 @@ import fr.acinq.lightning.db.InboundLiquidityOutgoingPayment
|
||||
import fr.acinq.lightning.utils.UUID
|
||||
import fr.acinq.lightning.utils.sat
|
||||
import fr.acinq.lightning.utils.toByteVector32
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
|
||||
class InboundLiquidityQueries(val database: PaymentsDatabase) {
|
||||
private val queries = database.inboundLiquidityOutgoingQueries
|
||||
class InboundLiquidityQueries(val database: PhoenixDatabase) {
|
||||
private val queries = database.inboundLiquidityOutgoingPaymentsQueries
|
||||
|
||||
fun add(payment: InboundLiquidityOutgoingPayment) {
|
||||
database.transaction {
|
||||
|
@ -21,13 +21,12 @@ import app.cash.sqldelight.coroutines.mapToList
|
||||
import fr.acinq.bitcoin.ByteVector32
|
||||
import fr.acinq.bitcoin.byteVector32
|
||||
import fr.acinq.lightning.db.IncomingPayment
|
||||
import fr.acinq.lightning.utils.msat
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class IncomingQueries(private val database: PaymentsDatabase) {
|
||||
class IncomingQueries(private val database: PhoenixDatabase) {
|
||||
|
||||
private val queries = database.incomingPaymentsQueries
|
||||
|
||||
|
@ -35,46 +35,46 @@ import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
enum class OutgoingDetailsTypeVersion {
|
||||
enum class LightningOutgoingDetailsTypeVersion {
|
||||
NORMAL_V0,
|
||||
KEYSEND_V0,
|
||||
SWAPOUT_V0,
|
||||
}
|
||||
|
||||
sealed class OutgoingDetailsData {
|
||||
sealed class LightningOutgoingDetailsData {
|
||||
|
||||
sealed class Normal : OutgoingDetailsData() {
|
||||
sealed class Normal : LightningOutgoingDetailsData() {
|
||||
@Serializable
|
||||
data class V0(val paymentRequest: String) : Normal()
|
||||
}
|
||||
|
||||
sealed class KeySend : OutgoingDetailsData() {
|
||||
sealed class KeySend : LightningOutgoingDetailsData() {
|
||||
@Serializable
|
||||
data class V0(@Serializable val preimage: ByteVector32) : KeySend()
|
||||
}
|
||||
|
||||
sealed class SwapOut : OutgoingDetailsData() {
|
||||
sealed class SwapOut : LightningOutgoingDetailsData() {
|
||||
@Serializable
|
||||
data class V0(val address: String, val paymentRequest: String, @Serializable val swapOutFee: Satoshi) : SwapOut()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** Deserialize the details of an outgoing payment. Return null if the details is for a legacy channel closing payment (see [deserializeLegacyClosingDetails]). */
|
||||
fun deserialize(typeVersion: OutgoingDetailsTypeVersion, blob: ByteArray): LightningOutgoingPayment.Details? = DbTypesHelper.decodeBlob(blob) { json, format ->
|
||||
fun deserialize(typeVersion: LightningOutgoingDetailsTypeVersion, blob: ByteArray): LightningOutgoingPayment.Details = DbTypesHelper.decodeBlob(blob) { json, format ->
|
||||
when (typeVersion) {
|
||||
OutgoingDetailsTypeVersion.NORMAL_V0 -> format.decodeFromString<Normal.V0>(json).let { LightningOutgoingPayment.Details.Normal(Bolt11Invoice.read(it.paymentRequest).get()) }
|
||||
OutgoingDetailsTypeVersion.KEYSEND_V0 -> format.decodeFromString<KeySend.V0>(json).let { LightningOutgoingPayment.Details.KeySend(it.preimage) }
|
||||
OutgoingDetailsTypeVersion.SWAPOUT_V0 -> format.decodeFromString<SwapOut.V0>(json).let { LightningOutgoingPayment.Details.SwapOut(it.address, Bolt11Invoice.read(it.paymentRequest).get(), it.swapOutFee) }
|
||||
LightningOutgoingDetailsTypeVersion.NORMAL_V0 -> format.decodeFromString<Normal.V0>(json).let { LightningOutgoingPayment.Details.Normal(Bolt11Invoice.read(it.paymentRequest).get()) }
|
||||
LightningOutgoingDetailsTypeVersion.KEYSEND_V0 -> format.decodeFromString<KeySend.V0>(json).let { LightningOutgoingPayment.Details.KeySend(it.preimage) }
|
||||
LightningOutgoingDetailsTypeVersion.SWAPOUT_V0 -> format.decodeFromString<SwapOut.V0>(json).let { LightningOutgoingPayment.Details.SwapOut(it.address, Bolt11Invoice.read(it.paymentRequest).get(), it.swapOutFee) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun LightningOutgoingPayment.Details.mapToDb(): Pair<OutgoingDetailsTypeVersion, ByteArray> = when (this) {
|
||||
is LightningOutgoingPayment.Details.Normal -> OutgoingDetailsTypeVersion.NORMAL_V0 to
|
||||
Json.encodeToString(OutgoingDetailsData.Normal.V0(paymentRequest.write())).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Details.KeySend -> OutgoingDetailsTypeVersion.KEYSEND_V0 to
|
||||
Json.encodeToString(OutgoingDetailsData.KeySend.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Details.SwapOut -> OutgoingDetailsTypeVersion.SWAPOUT_V0 to
|
||||
Json.encodeToString(OutgoingDetailsData.SwapOut.V0(address, paymentRequest.write(), swapOutFee)).toByteArray(Charsets.UTF_8)
|
||||
fun LightningOutgoingPayment.Details.mapToDb(): Pair<LightningOutgoingDetailsTypeVersion, ByteArray> = when (this) {
|
||||
is LightningOutgoingPayment.Details.Normal -> LightningOutgoingDetailsTypeVersion.NORMAL_V0 to
|
||||
Json.encodeToString(LightningOutgoingDetailsData.Normal.V0(paymentRequest.write())).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Details.KeySend -> LightningOutgoingDetailsTypeVersion.KEYSEND_V0 to
|
||||
Json.encodeToString(LightningOutgoingDetailsData.KeySend.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Details.SwapOut -> LightningOutgoingDetailsTypeVersion.SWAPOUT_V0 to
|
||||
Json.encodeToString(LightningOutgoingDetailsData.SwapOut.V0(address, paymentRequest.write(), swapOutFee)).toByteArray(Charsets.UTF_8)
|
||||
}
|
@ -31,33 +31,33 @@ import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
enum class OutgoingPartStatusTypeVersion {
|
||||
enum class LightningOutgoingPartStatusTypeVersion {
|
||||
SUCCEEDED_V0,
|
||||
FAILED_V0,
|
||||
}
|
||||
|
||||
sealed class OutgoingPartStatusData {
|
||||
sealed class LightningOutgoingPartStatusData {
|
||||
|
||||
sealed class Succeeded : OutgoingPartStatusData() {
|
||||
sealed class Succeeded : LightningOutgoingPartStatusData() {
|
||||
@Serializable
|
||||
data class V0(@Serializable val preimage: ByteVector32) : Succeeded()
|
||||
}
|
||||
|
||||
sealed class Failed : OutgoingPartStatusData() {
|
||||
sealed class Failed : LightningOutgoingPartStatusData() {
|
||||
@Serializable
|
||||
data class V0(val remoteFailureCode: Int?, val details: String) : Failed()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserialize(
|
||||
typeVersion: OutgoingPartStatusTypeVersion,
|
||||
typeVersion: LightningOutgoingPartStatusTypeVersion,
|
||||
blob: ByteArray, completedAt: Long
|
||||
): LightningOutgoingPayment.Part.Status = DbTypesHelper.decodeBlob(blob) { json, format ->
|
||||
when (typeVersion) {
|
||||
OutgoingPartStatusTypeVersion.SUCCEEDED_V0 -> format.decodeFromString<Succeeded.V0>(json).let {
|
||||
LightningOutgoingPartStatusTypeVersion.SUCCEEDED_V0 -> format.decodeFromString<Succeeded.V0>(json).let {
|
||||
LightningOutgoingPayment.Part.Status.Succeeded(it.preimage, completedAt)
|
||||
}
|
||||
OutgoingPartStatusTypeVersion.FAILED_V0 -> format.decodeFromString<Failed.V0>(json).let {
|
||||
LightningOutgoingPartStatusTypeVersion.FAILED_V0 -> format.decodeFromString<Failed.V0>(json).let {
|
||||
LightningOutgoingPayment.Part.Status.Failed(it.remoteFailureCode, it.details, completedAt)
|
||||
}
|
||||
}
|
||||
@ -65,8 +65,8 @@ sealed class OutgoingPartStatusData {
|
||||
}
|
||||
}
|
||||
|
||||
fun LightningOutgoingPayment.Part.Status.Succeeded.mapToDb() = OutgoingPartStatusTypeVersion.SUCCEEDED_V0 to
|
||||
Json.encodeToString(OutgoingPartStatusData.Succeeded.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
fun LightningOutgoingPayment.Part.Status.Succeeded.mapToDb() = LightningOutgoingPartStatusTypeVersion.SUCCEEDED_V0 to
|
||||
Json.encodeToString(LightningOutgoingPartStatusData.Succeeded.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
|
||||
fun LightningOutgoingPayment.Part.Status.Failed.mapToDb() = OutgoingPartStatusTypeVersion.FAILED_V0 to
|
||||
Json.encodeToString(OutgoingPartStatusData.Failed.V0(remoteFailureCode, details)).toByteArray(Charsets.UTF_8)
|
||||
fun LightningOutgoingPayment.Part.Status.Failed.mapToDb() = LightningOutgoingPartStatusTypeVersion.FAILED_V0 to
|
||||
Json.encodeToString(LightningOutgoingPartStatusData.Failed.V0(remoteFailureCode, details)).toByteArray(Charsets.UTF_8)
|
@ -25,16 +25,15 @@ import fr.acinq.lightning.ShortChannelId
|
||||
import fr.acinq.lightning.channel.ChannelException
|
||||
import fr.acinq.lightning.db.HopDesc
|
||||
import fr.acinq.lightning.db.LightningOutgoingPayment
|
||||
import fr.acinq.lightning.db.OutgoingPayment
|
||||
import fr.acinq.lightning.payment.OutgoingPaymentFailure
|
||||
import fr.acinq.lightning.utils.*
|
||||
import fr.acinq.lightning.wire.FailureMessage
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import fr.acinq.secp256k1.Hex
|
||||
|
||||
class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
class LightningOutgoingQueries(val database: PhoenixDatabase) {
|
||||
|
||||
private val queries = database.outgoingPaymentsQueries
|
||||
private val queries = database.lightningOutgoingPaymentsQueries
|
||||
|
||||
fun addLightningParts(parentId: UUID, parts: List<LightningOutgoingPayment.Part>) {
|
||||
if (parts.isEmpty()) return
|
||||
@ -135,12 +134,10 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
return result
|
||||
}
|
||||
|
||||
/** This method will ignore any parts that are not proper [LightningOutgoingPayment]. */
|
||||
fun getPaymentFromPartId(partId: UUID): LightningOutgoingPayment? {
|
||||
return queries.getLightningPart(part_id = partId.toString()).executeAsOneOrNull()?.let { part ->
|
||||
queries.getPayment(id = part.part_parent_id, Companion::mapLightningOutgoingPayment).executeAsList()
|
||||
}?.filterIsInstance<LightningOutgoingPayment>()?.let {
|
||||
// first ignore any legacy channel closing, then group by parent id
|
||||
}?.let {
|
||||
groupByRawLightningOutgoing(it).firstOrNull()
|
||||
}?.let {
|
||||
filterUselessParts(it)
|
||||
@ -156,17 +153,13 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
id = id.toString(),
|
||||
mapper = Companion::mapLightningOutgoingPayment
|
||||
).executeAsList().let { parts ->
|
||||
// only take regular LN payments parts, and group them
|
||||
parts.filterIsInstance<LightningOutgoingPayment>().let {
|
||||
groupByRawLightningOutgoing(it).firstOrNull()
|
||||
}?.let {
|
||||
groupByRawLightningOutgoing(parts).firstOrNull()?.let {
|
||||
filterUselessParts(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun listLightningOutgoingPayments(paymentHash: ByteVector32): List<LightningOutgoingPayment> {
|
||||
return queries.listPaymentsForPaymentHash(paymentHash.toByteArray(), Companion::mapLightningOutgoingPayment).executeAsList()
|
||||
.filterIsInstance<LightningOutgoingPayment>()
|
||||
.let { groupByRawLightningOutgoing(it) }
|
||||
}
|
||||
|
||||
@ -195,16 +188,15 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
recipient_amount_msat: Long,
|
||||
recipient_node_id: String,
|
||||
payment_hash: ByteArray,
|
||||
details_type: OutgoingDetailsTypeVersion,
|
||||
details_type: LightningOutgoingDetailsTypeVersion,
|
||||
details_blob: ByteArray,
|
||||
created_at: Long,
|
||||
completed_at: Long?,
|
||||
status_type: OutgoingStatusTypeVersion?,
|
||||
status_type: LightningOutgoingStatusTypeVersion?,
|
||||
status_blob: ByteArray?
|
||||
): LightningOutgoingPayment {
|
||||
val details = OutgoingDetailsData.deserialize(details_type, details_blob)
|
||||
return if (details != null) {
|
||||
LightningOutgoingPayment(
|
||||
val details = LightningOutgoingDetailsData.deserialize(details_type, details_blob)
|
||||
return LightningOutgoingPayment(
|
||||
id = UUID.fromString(id),
|
||||
recipientAmount = MilliSatoshi(recipient_amount_msat),
|
||||
recipient = PublicKey.parse(Hex.decode(recipient_node_id)),
|
||||
@ -213,7 +205,6 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
status = mapPaymentStatus(status_type, status_blob, completed_at),
|
||||
createdAt = created_at
|
||||
)
|
||||
} else throw IllegalArgumentException("cannot handle closing payment at this stage, use LegacyChannelCloseHelper")
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@ -222,11 +213,11 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
recipient_amount_msat: Long,
|
||||
recipient_node_id: String,
|
||||
payment_hash: ByteArray,
|
||||
details_type: OutgoingDetailsTypeVersion,
|
||||
details_type: LightningOutgoingDetailsTypeVersion,
|
||||
details_blob: ByteArray,
|
||||
created_at: Long,
|
||||
completed_at: Long?,
|
||||
status_type: OutgoingStatusTypeVersion?,
|
||||
status_type: LightningOutgoingStatusTypeVersion?,
|
||||
status_blob: ByteArray?,
|
||||
// lightning parts data, may be null
|
||||
lightning_part_id: String?,
|
||||
@ -234,16 +225,9 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
lightning_part_route: List<HopDesc>?,
|
||||
lightning_part_created_at: Long?,
|
||||
lightning_part_completed_at: Long?,
|
||||
lightning_part_status_type: OutgoingPartStatusTypeVersion?,
|
||||
lightning_part_status_type: LightningOutgoingPartStatusTypeVersion?,
|
||||
lightning_part_status_blob: ByteArray?,
|
||||
// closing tx parts data, may be null
|
||||
closingtx_part_id: String?,
|
||||
closingtx_part_tx_id: ByteArray?,
|
||||
closingtx_part_amount_sat: Long?,
|
||||
closingtx_part_closing_info_type: OutgoingPartClosingInfoTypeVersion?,
|
||||
closingtx_part_closing_info_blob: ByteArray?,
|
||||
closingtx_part_created_at: Long?
|
||||
): OutgoingPayment {
|
||||
): LightningOutgoingPayment {
|
||||
|
||||
val parts = if (lightning_part_id != null && lightning_part_amount_msat != null && lightning_part_route != null && lightning_part_created_at != null) {
|
||||
listOf(
|
||||
@ -281,7 +265,7 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
route: List<HopDesc>,
|
||||
createdAt: Long,
|
||||
completedAt: Long?,
|
||||
statusType: OutgoingPartStatusTypeVersion?,
|
||||
statusType: LightningOutgoingPartStatusTypeVersion?,
|
||||
statusBlob: ByteArray?
|
||||
): LightningOutgoingPayment.Part {
|
||||
return LightningOutgoingPayment.Part(
|
||||
@ -298,22 +282,22 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
}
|
||||
|
||||
private fun mapPaymentStatus(
|
||||
statusType: OutgoingStatusTypeVersion?,
|
||||
statusType: LightningOutgoingStatusTypeVersion?,
|
||||
statusBlob: ByteArray?,
|
||||
completedAt: Long?,
|
||||
): LightningOutgoingPayment.Status = when {
|
||||
completedAt == null && statusType == null && statusBlob == null -> LightningOutgoingPayment.Status.Pending
|
||||
completedAt != null && statusType != null && statusBlob != null -> OutgoingStatusData.deserialize(statusType, statusBlob, completedAt)
|
||||
completedAt != null && statusType != null && statusBlob != null -> LightningOutgoingStatusData.deserialize(statusType, statusBlob, completedAt)
|
||||
else -> throw UnhandledOutgoingStatus(completedAt, statusType, statusBlob)
|
||||
}
|
||||
|
||||
private fun mapLightningPartStatus(
|
||||
statusType: OutgoingPartStatusTypeVersion?,
|
||||
statusType: LightningOutgoingPartStatusTypeVersion?,
|
||||
statusBlob: ByteArray?,
|
||||
completedAt: Long?,
|
||||
): LightningOutgoingPayment.Part.Status = when {
|
||||
completedAt == null && statusType == null && statusBlob == null -> LightningOutgoingPayment.Part.Status.Pending
|
||||
completedAt != null && statusType != null && statusBlob != null -> OutgoingPartStatusData.deserialize(statusType, statusBlob, completedAt)
|
||||
completedAt != null && statusType != null && statusBlob != null -> LightningOutgoingPartStatusData.deserialize(statusType, statusBlob, completedAt)
|
||||
else -> throw UnhandledOutgoingPartStatus(statusType, statusBlob, completedAt)
|
||||
}
|
||||
|
||||
@ -336,8 +320,8 @@ class OutgoingQueries(val database: PaymentsDatabase) {
|
||||
}
|
||||
}
|
||||
|
||||
data class UnhandledOutgoingStatus(val completedAt: Long?, val statusTypeVersion: OutgoingStatusTypeVersion?, val statusData: ByteArray?) :
|
||||
data class UnhandledOutgoingStatus(val completedAt: Long?, val statusTypeVersion: LightningOutgoingStatusTypeVersion?, val statusData: ByteArray?) :
|
||||
RuntimeException("cannot map outgoing payment status data with completed_at=$completedAt status_type=$statusTypeVersion status=$statusData")
|
||||
|
||||
data class UnhandledOutgoingPartStatus(val status_type: OutgoingPartStatusTypeVersion?, val status_blob: ByteArray?, val completedAt: Long?) :
|
||||
data class UnhandledOutgoingPartStatus(val status_type: LightningOutgoingPartStatusTypeVersion?, val status_blob: ByteArray?, val completedAt: Long?) :
|
||||
RuntimeException("cannot map outgoing part status data [ completed_at=$completedAt status_type=$status_type status_blob=$status_blob]")
|
@ -22,7 +22,6 @@
|
||||
package fr.acinq.lightning.bin.db.payments
|
||||
|
||||
import fr.acinq.bitcoin.ByteVector32
|
||||
import fr.acinq.bitcoin.Satoshi
|
||||
import fr.acinq.lightning.bin.db.payments.DbTypesHelper.decodeBlob
|
||||
import fr.acinq.lightning.bin.db.serializers.v1.ByteVector32Serializer
|
||||
import fr.acinq.lightning.bin.db.serializers.v1.SatoshiSerializer
|
||||
@ -32,54 +31,35 @@ import io.ktor.utils.io.charsets.*
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
enum class OutgoingStatusTypeVersion {
|
||||
enum class LightningOutgoingStatusTypeVersion {
|
||||
SUCCEEDED_OFFCHAIN_V0,
|
||||
FAILED_V0,
|
||||
}
|
||||
|
||||
sealed class OutgoingStatusData {
|
||||
sealed class LightningOutgoingStatusData {
|
||||
|
||||
sealed class SucceededOffChain : OutgoingStatusData() {
|
||||
sealed class SucceededOffChain : LightningOutgoingStatusData() {
|
||||
@Serializable
|
||||
data class V0(@Serializable val preimage: ByteVector32) : SucceededOffChain()
|
||||
}
|
||||
|
||||
sealed class SucceededOnChain : OutgoingStatusData() {
|
||||
@Serializable
|
||||
data class V0(
|
||||
val txIds: List<@Serializable ByteVector32>,
|
||||
@Serializable val claimed: Satoshi,
|
||||
val closingType: String
|
||||
) : SucceededOnChain()
|
||||
|
||||
@Serializable
|
||||
object V1 : SucceededOnChain()
|
||||
}
|
||||
|
||||
sealed class Failed : OutgoingStatusData() {
|
||||
sealed class Failed : LightningOutgoingStatusData() {
|
||||
@Serializable
|
||||
data class V0(val reason: String) : Failed()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/** Extract valuable data from old outgoing payments status that represent closing transactions. */
|
||||
fun deserializeLegacyClosingStatus(blob: ByteArray): SucceededOnChain.V0 = decodeBlob(blob) { json, format ->
|
||||
val data = format.decodeFromString<SucceededOnChain.V0>(json)
|
||||
data
|
||||
}
|
||||
|
||||
fun deserialize(typeVersion: OutgoingStatusTypeVersion, blob: ByteArray, completedAt: Long): LightningOutgoingPayment.Status = decodeBlob(blob) { json, format ->
|
||||
fun deserialize(typeVersion: LightningOutgoingStatusTypeVersion, blob: ByteArray, completedAt: Long): LightningOutgoingPayment.Status = decodeBlob(blob) { json, format ->
|
||||
@Suppress("DEPRECATION")
|
||||
when (typeVersion) {
|
||||
OutgoingStatusTypeVersion.SUCCEEDED_OFFCHAIN_V0 -> format.decodeFromString<SucceededOffChain.V0>(json).let {
|
||||
LightningOutgoingStatusTypeVersion.SUCCEEDED_OFFCHAIN_V0 -> format.decodeFromString<SucceededOffChain.V0>(json).let {
|
||||
LightningOutgoingPayment.Status.Completed.Succeeded.OffChain(it.preimage, completedAt)
|
||||
}
|
||||
OutgoingStatusTypeVersion.FAILED_V0 -> format.decodeFromString<Failed.V0>(json).let {
|
||||
LightningOutgoingStatusTypeVersion.FAILED_V0 -> format.decodeFromString<Failed.V0>(json).let {
|
||||
LightningOutgoingPayment.Status.Completed.Failed(deserializeFinalFailure(it.reason), completedAt)
|
||||
}
|
||||
}
|
||||
@ -101,10 +81,9 @@ sealed class OutgoingStatusData {
|
||||
}
|
||||
}
|
||||
|
||||
fun LightningOutgoingPayment.Status.Completed.mapToDb(): Pair<OutgoingStatusTypeVersion, ByteArray> = when (this) {
|
||||
is LightningOutgoingPayment.Status.Completed.Succeeded.OffChain -> OutgoingStatusTypeVersion.SUCCEEDED_OFFCHAIN_V0 to
|
||||
Json.encodeToString(OutgoingStatusData.SucceededOffChain.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Status.Completed.Failed -> OutgoingStatusTypeVersion.FAILED_V0 to
|
||||
Json.encodeToString(OutgoingStatusData.Failed.V0(OutgoingStatusData.serializeFinalFailure(reason))).toByteArray(Charsets.UTF_8)
|
||||
fun LightningOutgoingPayment.Status.Completed.mapToDb(): Pair<LightningOutgoingStatusTypeVersion, ByteArray> = when (this) {
|
||||
is LightningOutgoingPayment.Status.Completed.Succeeded.OffChain -> LightningOutgoingStatusTypeVersion.SUCCEEDED_OFFCHAIN_V0 to
|
||||
Json.encodeToString(LightningOutgoingStatusData.SucceededOffChain.V0(preimage)).toByteArray(Charsets.UTF_8)
|
||||
is LightningOutgoingPayment.Status.Completed.Failed -> LightningOutgoingStatusTypeVersion.FAILED_V0 to
|
||||
Json.encodeToString(LightningOutgoingStatusData.Failed.V0(LightningOutgoingStatusData.serializeFinalFailure(reason))).toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ import app.cash.sqldelight.coroutines.asFlow
|
||||
import app.cash.sqldelight.coroutines.mapToList
|
||||
import fr.acinq.bitcoin.TxId
|
||||
import fr.acinq.lightning.bin.db.WalletPaymentId
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
class LinkTxToPaymentQueries(val database: PaymentsDatabase) {
|
||||
class LinkTxToPaymentQueries(val database: PhoenixDatabase) {
|
||||
private val linkTxQueries = database.linkTxToPaymentQueries
|
||||
|
||||
fun listUnconfirmedTxs(): Flow<List<ByteArray>> {
|
||||
|
@ -3,9 +3,9 @@ package fr.acinq.lightning.bin.db.payments
|
||||
import fr.acinq.lightning.bin.db.PaymentMetadata
|
||||
import fr.acinq.lightning.bin.db.WalletPaymentId
|
||||
import fr.acinq.lightning.utils.currentTimestampMillis
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
|
||||
class PaymentsMetadataQueries(private val database: PaymentsDatabase) {
|
||||
class PaymentsMetadataQueries(private val database: PhoenixDatabase) {
|
||||
|
||||
private val queries = database.paymentsMetadataQueries
|
||||
|
||||
|
@ -21,9 +21,9 @@ import fr.acinq.lightning.db.SpliceCpfpOutgoingPayment
|
||||
import fr.acinq.lightning.utils.UUID
|
||||
import fr.acinq.lightning.utils.sat
|
||||
import fr.acinq.lightning.utils.toByteVector32
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
|
||||
class SpliceCpfpOutgoingQueries(val database: PaymentsDatabase) {
|
||||
class SpliceCpfpOutgoingQueries(val database: PhoenixDatabase) {
|
||||
private val cpfpQueries = database.spliceCpfpOutgoingPaymentsQueries
|
||||
|
||||
fun addCpfpPayment(payment: SpliceCpfpOutgoingPayment) {
|
||||
|
@ -21,9 +21,9 @@ import fr.acinq.lightning.db.SpliceOutgoingPayment
|
||||
import fr.acinq.lightning.utils.UUID
|
||||
import fr.acinq.lightning.utils.sat
|
||||
import fr.acinq.lightning.utils.toByteVector32
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
|
||||
class SpliceOutgoingQueries(val database: PaymentsDatabase) {
|
||||
class SpliceOutgoingQueries(val database: PhoenixDatabase) {
|
||||
private val spliceOutQueries = database.spliceOutgoingPaymentsQueries
|
||||
|
||||
fun addSpliceOutgoingPayment(payment: SpliceOutgoingPayment) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import fr.acinq.lightning.bin.db.payments.OutgoingPartClosingInfoTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.ClosingInfoTypeVersion;
|
||||
|
||||
-- Store in a flat row outgoing payments standing for channel-closing.
|
||||
-- There are no complex json columns like in the outgoing_payments table.
|
||||
@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS channel_close_outgoing_payments (
|
||||
confirmed_at INTEGER DEFAULT NULL,
|
||||
locked_at INTEGER DEFAULT NULL,
|
||||
channel_id BLOB NOT NULL,
|
||||
closing_info_type TEXT AS OutgoingPartClosingInfoTypeVersion NOT NULL,
|
||||
closing_info_type TEXT AS ClosingInfoTypeVersion NOT NULL,
|
||||
closing_info_blob BLOB NOT NULL
|
||||
);
|
||||
|
@ -1,36 +1,35 @@
|
||||
import fr.acinq.lightning.db.HopDesc;
|
||||
import fr.acinq.lightning.bin.db.payments.OutgoingDetailsTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.OutgoingPartClosingInfoTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.OutgoingPartStatusTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.OutgoingStatusTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.LightningOutgoingDetailsTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.LightningOutgoingPartStatusTypeVersion;
|
||||
import fr.acinq.lightning.bin.db.payments.LightningOutgoingStatusTypeVersion;
|
||||
import kotlin.collections.List;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
-- outgoing payments
|
||||
-- Stores an outgoing payment in a flat row. Some columns can be null.
|
||||
CREATE TABLE IF NOT EXISTS outgoing_payments (
|
||||
CREATE TABLE IF NOT EXISTS lightning_outgoing_payments (
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
recipient_amount_msat INTEGER NOT NULL,
|
||||
recipient_node_id TEXT NOT NULL,
|
||||
payment_hash BLOB NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
-- details
|
||||
details_type TEXT AS OutgoingDetailsTypeVersion NOT NULL,
|
||||
details_type TEXT AS LightningOutgoingDetailsTypeVersion NOT NULL,
|
||||
details_blob BLOB NOT NULL,
|
||||
-- status
|
||||
completed_at INTEGER DEFAULT NULL,
|
||||
status_type TEXT AS OutgoingStatusTypeVersion DEFAULT NULL,
|
||||
status_type TEXT AS LightningOutgoingStatusTypeVersion DEFAULT NULL,
|
||||
status_blob BLOB DEFAULT NULL
|
||||
);
|
||||
|
||||
-- Create indexes to optimize the queries in AggregatedQueries.
|
||||
-- Tip: Use "explain query plan" to ensure they're actually being used.
|
||||
CREATE INDEX IF NOT EXISTS outgoing_payments_filter_idx
|
||||
ON outgoing_payments(completed_at);
|
||||
ON lightning_outgoing_payments(completed_at);
|
||||
|
||||
-- Stores the lightning parts that make up a lightning payment
|
||||
CREATE TABLE IF NOT EXISTS outgoing_payment_parts (
|
||||
CREATE TABLE IF NOT EXISTS lightning_outgoing_payment_parts (
|
||||
part_id TEXT NOT NULL PRIMARY KEY,
|
||||
part_parent_id TEXT NOT NULL,
|
||||
part_amount_msat INTEGER NOT NULL,
|
||||
@ -38,24 +37,10 @@ CREATE TABLE IF NOT EXISTS outgoing_payment_parts (
|
||||
part_created_at INTEGER NOT NULL,
|
||||
-- status
|
||||
part_completed_at INTEGER DEFAULT NULL,
|
||||
part_status_type TEXT AS OutgoingPartStatusTypeVersion DEFAULT NULL,
|
||||
part_status_type TEXT AS LightningOutgoingPartStatusTypeVersion DEFAULT NULL,
|
||||
part_status_blob BLOB DEFAULT NULL,
|
||||
|
||||
FOREIGN KEY(part_parent_id) REFERENCES outgoing_payments(id)
|
||||
);
|
||||
|
||||
-- !! This table is legacy, and will only contain old payments. See ChannelCloseOutgoingPayment.sq for the new table.
|
||||
-- Stores the transactions that close a channel
|
||||
CREATE TABLE IF NOT EXISTS outgoing_payment_closing_tx_parts (
|
||||
part_id TEXT NOT NULL PRIMARY KEY,
|
||||
part_parent_id TEXT NOT NULL,
|
||||
part_tx_id BLOB NOT NULL,
|
||||
part_amount_sat INTEGER NOT NULL,
|
||||
part_closing_info_type TEXT AS OutgoingPartClosingInfoTypeVersion NOT NULL,
|
||||
part_closing_info_blob BLOB NOT NULL,
|
||||
part_created_at INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(part_parent_id) REFERENCES outgoing_payments(id)
|
||||
FOREIGN KEY(part_parent_id) REFERENCES lightning_outgoing_payments(id)
|
||||
);
|
||||
|
||||
-- A FOREIGN KEY does NOT create an implicit index.
|
||||
@ -64,17 +49,16 @@ CREATE TABLE IF NOT EXISTS outgoing_payment_closing_tx_parts (
|
||||
-- > Indices are not required for child key columns but they are almost always beneficial.
|
||||
-- > [...] So, in most real systems, an index should be created on the child key columns
|
||||
-- > of each foreign key constraint.
|
||||
CREATE INDEX IF NOT EXISTS parent_id_idx ON outgoing_payment_parts(part_parent_id);
|
||||
CREATE INDEX IF NOT EXISTS parent_id_idx ON outgoing_payment_closing_tx_parts(part_parent_id);
|
||||
CREATE INDEX IF NOT EXISTS parent_id_idx ON lightning_outgoing_payment_parts(part_parent_id);
|
||||
|
||||
-- queries for outgoing payments
|
||||
|
||||
hasPayment:
|
||||
SELECT COUNT(*) FROM outgoing_payments
|
||||
SELECT COUNT(*) FROM lightning_outgoing_payments
|
||||
WHERE id = ?;
|
||||
|
||||
insertPayment:
|
||||
INSERT INTO outgoing_payments (
|
||||
INSERT INTO lightning_outgoing_payments (
|
||||
id,
|
||||
recipient_amount_msat,
|
||||
recipient_node_id,
|
||||
@ -85,23 +69,23 @@ INSERT INTO outgoing_payments (
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||
|
||||
updatePayment:
|
||||
UPDATE outgoing_payments SET completed_at=?, status_type=?, status_blob=? WHERE id=?;
|
||||
UPDATE lightning_outgoing_payments SET completed_at=?, status_type=?, status_blob=? WHERE id=?;
|
||||
|
||||
scanCompleted:
|
||||
SELECT id, completed_at
|
||||
FROM outgoing_payments
|
||||
FROM lightning_outgoing_payments
|
||||
WHERE completed_at IS NOT NULL;
|
||||
|
||||
deletePayment:
|
||||
DELETE FROM outgoing_payments WHERE id = ?;
|
||||
DELETE FROM lightning_outgoing_payments WHERE id = ?;
|
||||
|
||||
-- queries for lightning parts
|
||||
|
||||
countLightningPart:
|
||||
SELECT COUNT(*) FROM outgoing_payment_parts WHERE part_id = ?;
|
||||
SELECT COUNT(*) FROM lightning_outgoing_payment_parts WHERE part_id = ?;
|
||||
|
||||
insertLightningPart:
|
||||
INSERT INTO outgoing_payment_parts (
|
||||
INSERT INTO lightning_outgoing_payment_parts (
|
||||
part_id,
|
||||
part_parent_id,
|
||||
part_amount_msat,
|
||||
@ -110,33 +94,17 @@ INSERT INTO outgoing_payment_parts (
|
||||
VALUES (?, ?, ?, ?, ?);
|
||||
|
||||
updateLightningPart:
|
||||
UPDATE outgoing_payment_parts
|
||||
UPDATE lightning_outgoing_payment_parts
|
||||
SET part_status_type=?,
|
||||
part_status_blob=?,
|
||||
part_completed_at=?
|
||||
WHERE part_id=?;
|
||||
|
||||
getLightningPart:
|
||||
SELECT * FROM outgoing_payment_parts WHERE part_id=?;
|
||||
SELECT * FROM lightning_outgoing_payment_parts WHERE part_id=?;
|
||||
|
||||
deleteLightningPartsForParentId:
|
||||
DELETE FROM outgoing_payment_parts WHERE part_parent_id = ?;
|
||||
|
||||
-- queries for closing tx parts
|
||||
|
||||
countClosingTxPart:
|
||||
SELECT COUNT(*) FROM outgoing_payment_closing_tx_parts WHERE part_id = ?;
|
||||
|
||||
insertClosingTxPart:
|
||||
INSERT INTO outgoing_payment_closing_tx_parts (
|
||||
part_id,
|
||||
part_parent_id,
|
||||
part_tx_id,
|
||||
part_amount_sat,
|
||||
part_closing_info_type,
|
||||
part_closing_info_blob,
|
||||
part_created_at
|
||||
) VALUES (:id, :parent_id, :tx_id, :amount_msat, :closing_info_type, :closing_info_blob, :created_at);
|
||||
DELETE FROM lightning_outgoing_payment_parts WHERE part_parent_id = ?;
|
||||
|
||||
-- queries mixing outgoing payments and parts
|
||||
|
||||
@ -151,12 +119,12 @@ SELECT id,
|
||||
completed_at,
|
||||
status_type,
|
||||
status_blob
|
||||
FROM outgoing_payments
|
||||
FROM lightning_outgoing_payments
|
||||
WHERE id=?;
|
||||
|
||||
getOldestCompletedDate:
|
||||
SELECT completed_at
|
||||
FROM outgoing_payments AS o
|
||||
FROM lightning_outgoing_payments AS o
|
||||
WHERE completed_at IS NOT NULL
|
||||
ORDER BY o.completed_at ASC
|
||||
LIMIT 1;
|
||||
@ -179,17 +147,9 @@ SELECT parent.id,
|
||||
lightning_parts.part_created_at AS lightning_part_created_at,
|
||||
lightning_parts.part_completed_at AS lightning_part_completed_at,
|
||||
lightning_parts.part_status_type AS lightning_part_status_type,
|
||||
lightning_parts.part_status_blob AS lightning_part_status_blob,
|
||||
-- closing tx parts
|
||||
closing_parts.part_id AS closingtx_part_id,
|
||||
closing_parts.part_tx_id AS closingtx_tx_id,
|
||||
closing_parts.part_amount_sat AS closingtx_amount_sat,
|
||||
closing_parts.part_closing_info_type AS closingtx_info_type,
|
||||
closing_parts.part_closing_info_blob AS closingtx_info_blob,
|
||||
closing_parts.part_created_at AS closingtx_created_at
|
||||
FROM outgoing_payments AS parent
|
||||
LEFT OUTER JOIN outgoing_payment_parts AS lightning_parts ON lightning_parts.part_parent_id = parent.id
|
||||
LEFT OUTER JOIN outgoing_payment_closing_tx_parts AS closing_parts ON closing_parts.part_parent_id = parent.id
|
||||
lightning_parts.part_status_blob AS lightning_part_status_blob
|
||||
FROM lightning_outgoing_payments AS parent
|
||||
LEFT OUTER JOIN lightning_outgoing_payment_parts AS lightning_parts ON lightning_parts.part_parent_id = parent.id
|
||||
WHERE parent.id=?;
|
||||
|
||||
listPaymentsForPaymentHash:
|
||||
@ -210,17 +170,9 @@ SELECT parent.id,
|
||||
lightning_parts.part_created_at AS lightning_part_created_at,
|
||||
lightning_parts.part_completed_at AS lightning_part_completed_at,
|
||||
lightning_parts.part_status_type AS lightning_part_status_type,
|
||||
lightning_parts.part_status_blob AS lightning_part_status_blob,
|
||||
-- closing tx parts
|
||||
closing_parts.part_id AS closingtx_part_id,
|
||||
closing_parts.part_tx_id AS closingtx_tx_id,
|
||||
closing_parts.part_amount_sat AS closingtx_amount_sat,
|
||||
closing_parts.part_closing_info_type AS closingtx_info_type,
|
||||
closing_parts.part_closing_info_blob AS closingtx_info_blob,
|
||||
closing_parts.part_created_at AS closingtx_created_at
|
||||
FROM outgoing_payments AS parent
|
||||
LEFT OUTER JOIN outgoing_payment_parts AS lightning_parts ON lightning_parts.part_parent_id = parent.id
|
||||
LEFT OUTER JOIN outgoing_payment_closing_tx_parts AS closing_parts ON closing_parts.part_parent_id = parent.id
|
||||
lightning_parts.part_status_blob AS lightning_part_status_blob
|
||||
FROM lightning_outgoing_payments AS parent
|
||||
LEFT OUTER JOIN lightning_outgoing_payment_parts AS lightning_parts ON lightning_parts.part_parent_id = parent.id
|
||||
WHERE payment_hash=?;
|
||||
|
||||
-- use this in a `transaction` block to know how many rows were changed after an UPDATE
|
@ -2,8 +2,7 @@ package fr.acinq.lightning.bin
|
||||
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import fr.acinq.phoenix.db.ChannelsDatabase
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import okio.Path
|
||||
import okio.Path.Companion.toPath
|
||||
|
||||
@ -12,13 +11,6 @@ actual val homeDirectory: Path = System.getProperty("user.home").toPath()
|
||||
actual fun createAppDbDriver(dir: Path): SqlDriver {
|
||||
val path = dir / "phoenix.db"
|
||||
val driver = JdbcSqliteDriver("jdbc:sqlite:$path")
|
||||
ChannelsDatabase.Schema.create(driver)
|
||||
return driver
|
||||
}
|
||||
|
||||
actual fun createPaymentsDbDriver(dir: Path): SqlDriver {
|
||||
val path = dir / "payments.db"
|
||||
val driver = JdbcSqliteDriver("jdbc:sqlite:$path")
|
||||
PaymentsDatabase.Schema.create(driver)
|
||||
PhoenixDatabase.Schema.create(driver)
|
||||
return driver
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ package fr.acinq.lightning.bin
|
||||
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.driver.native.NativeSqliteDriver
|
||||
import fr.acinq.phoenix.db.ChannelsDatabase
|
||||
import fr.acinq.phoenix.db.PaymentsDatabase
|
||||
import fr.acinq.phoenix.db.PhoenixDatabase
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.toKString
|
||||
import okio.Path
|
||||
@ -15,13 +14,7 @@ import platform.posix.setenv
|
||||
actual val homeDirectory: Path = setenv("KTOR_LOG_LEVEL", "WARN", 1).let { getenv("HOME")?.toKString()!!.toPath() }
|
||||
|
||||
actual fun createAppDbDriver(dir: Path): SqlDriver {
|
||||
return NativeSqliteDriver(ChannelsDatabase.Schema, "phoenix.db",
|
||||
onConfiguration = { it.copy(extendedConfig = it.extendedConfig.copy(basePath = dir.toString())) }
|
||||
)
|
||||
}
|
||||
|
||||
actual fun createPaymentsDbDriver(dir: Path): SqlDriver {
|
||||
return NativeSqliteDriver(PaymentsDatabase.Schema, "payments.db",
|
||||
return NativeSqliteDriver(PhoenixDatabase.Schema, "phoenix.db",
|
||||
onConfiguration = { it.copy(extendedConfig = it.extendedConfig.copy(basePath = dir.toString())) }
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user