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