From ae733602913ec563621a4fa56d6e998a048573df Mon Sep 17 00:00:00 2001 From: t-bast Date: Fri, 1 Sep 2023 18:20:54 +0200 Subject: [PATCH] Use `TxId` and `TxHash` objects This helps disambiguate when each is used. Even though confusingly, Electrum calls its field `tx_hash` while actually returning the `txid`. --- build.gradle.kts | 4 +- .../lightning/blockchain/WatcherTypes.kt | 8 +-- .../blockchain/electrum/ElectrumClient.kt | 6 +- .../electrum/ElectrumClientExtensions.kt | 4 +- .../blockchain/electrum/ElectrumDataTypes.kt | 55 +++++++++-------- .../blockchain/electrum/ElectrumMiniWallet.kt | 4 +- .../blockchain/electrum/ElectrumWatcher.kt | 8 +-- .../blockchain/electrum/IElectrumClient.kt | 7 ++- .../blockchain/electrum/SwapInManager.kt | 4 +- .../acinq/lightning/channel/ChannelAction.kt | 18 +++--- .../acinq/lightning/channel/ChannelCommand.kt | 9 +-- .../lightning/channel/ChannelException.kt | 18 +++--- .../fr/acinq/lightning/channel/Commitments.kt | 54 ++++++++++++---- .../fr/acinq/lightning/channel/Helpers.kt | 48 +-------------- .../acinq/lightning/channel/InteractiveTx.kt | 28 ++++----- .../acinq/lightning/channel/states/Channel.kt | 19 +++--- .../acinq/lightning/channel/states/Normal.kt | 11 ++-- .../acinq/lightning/channel/states/Syncing.kt | 2 +- .../channel/states/WaitForFundingConfirmed.kt | 4 +- .../channel/states/WaitForFundingSigned.kt | 2 +- .../fr/acinq/lightning/db/PaymentsDb.kt | 21 +++---- .../kotlin/fr/acinq/lightning/io/Peer.kt | 2 +- .../acinq/lightning/json/JsonSerializers.kt | 8 ++- .../acinq/lightning/payment/PaymentRequest.kt | 2 +- .../acinq/lightning/router/Announcements.kt | 6 +- .../serialization/v2/ChannelState.kt | 5 +- .../serialization/v2/bitcoinKSerializers.kt | 12 ++++ .../serialization/v3/ChannelState.kt | 5 +- .../serialization/v3/bitcoinKSerializers.kt | 12 ++++ .../serialization/v4/Deserialization.kt | 10 +-- .../serialization/v4/Serialization.kt | 8 ++- .../fr/acinq/lightning/utils/jsonrpc.kt | 3 +- .../fr/acinq/lightning/wire/ChannelTlv.kt | 14 +++-- .../acinq/lightning/wire/InteractiveTxTlv.kt | 7 +-- .../acinq/lightning/wire/LightningCodecs.kt | 14 +++++ .../acinq/lightning/wire/LightningMessages.kt | 61 +++++++++---------- .../blockchain/electrum/ElectrumClientTest.kt | 30 ++++----- .../electrum/ElectrumMiniWalletTest.kt | 24 ++++---- .../electrum/ElectrumRequestTest.kt | 3 +- .../ElectrumWatcherIntegrationTest.kt | 2 +- .../electrum/SwapInManagerTestsCommon.kt | 20 +++--- .../channel/ChannelDataTestsCommon.kt | 2 +- .../channel/CommitmentsTestsCommon.kt | 12 ++-- .../lightning/channel/HelpersTestsCommon.kt | 17 ++---- .../channel/InteractiveTxTestsCommon.kt | 16 ++--- .../fr/acinq/lightning/channel/TestsHelper.kt | 8 +-- .../channel/states/ClosingTestsCommon.kt | 14 ++--- .../channel/states/NormalTestsCommon.kt | 2 +- .../channel/states/SpliceTestsCommon.kt | 24 ++++---- .../channel/states/SyncingTestsCommon.kt | 5 +- .../states/WaitForChannelReadyTestsCommon.kt | 3 +- .../WaitForFundingConfirmedTestsCommon.kt | 2 +- .../WaitForFundingCreatedTestsCommon.kt | 9 +-- .../states/WaitForFundingSignedTestsCommon.kt | 4 +- .../acinq/lightning/db/InMemoryPaymentsDb.kt | 6 +- .../lightning/db/PaymentsDbTestsCommon.kt | 4 +- .../IncomingPaymentHandlerTestsCommon.kt | 14 ++--- .../transactions/TransactionsTestsCommon.kt | 22 +++---- .../wire/LightningCodecsTestsCommon.kt | 44 ++++++------- 59 files changed, 404 insertions(+), 386 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 83d1fc093..7955cabf9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ kotlin { val commonMain by sourceSets.getting { dependencies { - api("fr.acinq.bitcoin:bitcoin-kmp:0.13.0") // when upgrading, keep secp256k1-kmp-jni-jvm in sync below + api("fr.acinq.bitcoin:bitcoin-kmp:0.14.0") // when upgrading, keep secp256k1-kmp-jni-jvm in sync below api("org.kodein.log:canard:0.18.0") api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion") api("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") @@ -63,7 +63,7 @@ kotlin { api(ktor("client-okhttp")) api(ktor("network")) api(ktor("network-tls")) - implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:0.10.1") + implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:0.11.0") implementation("org.slf4j:slf4j-api:1.7.36") api("org.xerial:sqlite-jdbc:3.32.3.2") } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/WatcherTypes.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/WatcherTypes.kt index 963720ca7..9919381d2 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/WatcherTypes.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/WatcherTypes.kt @@ -23,7 +23,7 @@ sealed class Watch { // we need a public key script to use electrum apis data class WatchConfirmed( override val channelId: ByteVector32, - val txId: ByteVector32, + val txId: TxId, val publicKeyScript: ByteVector, val minDepth: Long, override val event: BitcoinEvent, @@ -59,7 +59,7 @@ data class WatchConfirmed( data class WatchSpent( override val channelId: ByteVector32, - val txId: ByteVector32, + val txId: TxId, val outputIndex: Int, val publicKeyScript: ByteVector, override val event: BitcoinEvent @@ -83,7 +83,3 @@ sealed class WatchEvent { data class WatchEventConfirmed(override val channelId: ByteVector32, override val event: BitcoinEvent, val blockHeight: Int, val txIndex: Int, val tx: Transaction) : WatchEvent() data class WatchEventSpent(override val channelId: ByteVector32, override val event: BitcoinEvent, val tx: Transaction) : WatchEvent() - -data class PublishAsap(val tx: Transaction) -data class GetTxWithMeta(val channelId: ByteVector32, val txid: ByteVector32) -data class GetTxWithMetaResponse(val txid: ByteVector32, val tx_opt: Transaction?, val lastBlockTimestamp: Long) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClient.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClient.kt index b8a9be628..f72e56afa 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClient.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClient.kt @@ -266,19 +266,19 @@ class ElectrumClient( } } - override suspend fun getTx(txid: ByteVector32): Transaction? = rpcCall(GetTransaction(txid)).right?.tx + override suspend fun getTx(txId: TxId): Transaction? = rpcCall(GetTransaction(txId)).right?.tx override suspend fun getHeader(blockHeight: Int): BlockHeader? = rpcCall(GetHeader(blockHeight)).right?.header override suspend fun getHeaders(startHeight: Int, count: Int): List = rpcCall(GetHeaders(startHeight, count)).right?.headers ?: listOf() - override suspend fun getMerkle(txid: ByteVector32, blockHeight: Int, contextOpt: Transaction?): GetMerkleResponse? = rpcCall(GetMerkle(txid, blockHeight, contextOpt)).right + override suspend fun getMerkle(txId: TxId, blockHeight: Int, contextOpt: Transaction?): GetMerkleResponse? = rpcCall(GetMerkle(txId, blockHeight, contextOpt)).right override suspend fun getScriptHashHistory(scriptHash: ByteVector32): List = rpcCall(GetScriptHashHistory(scriptHash)).right?.history ?: listOf() override suspend fun getScriptHashUnspents(scriptHash: ByteVector32): List = rpcCall(ScriptHashListUnspent(scriptHash)).right?.unspents ?: listOf() - override suspend fun broadcastTransaction(tx: Transaction): ByteVector32 = rpcCall(BroadcastTransaction(tx)).right?.tx?.txid ?: tx.txid + override suspend fun broadcastTransaction(tx: Transaction): TxId = rpcCall(BroadcastTransaction(tx)).right?.tx?.txid ?: tx.txid override suspend fun estimateFees(confirmations: Int): FeeratePerKw? = rpcCall(EstimateFees(confirmations)).right?.feerate diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientExtensions.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientExtensions.kt index c23d55c8a..0928a94b7 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientExtensions.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientExtensions.kt @@ -1,8 +1,8 @@ package fr.acinq.lightning.blockchain.electrum -import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.Satoshi import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.blockchain.fee.FeeratePerKw import fr.acinq.lightning.channel.Commitments import fr.acinq.lightning.channel.LocalFundingStatus @@ -10,7 +10,7 @@ import fr.acinq.lightning.transactions.Transactions import fr.acinq.lightning.utils.MDCLogger import fr.acinq.lightning.utils.sat -suspend fun IElectrumClient.getConfirmations(txId: ByteVector32): Int? = getTx(txId)?.let { tx -> getConfirmations(tx) } +suspend fun IElectrumClient.getConfirmations(txId: TxId): Int? = getTx(txId)?.let { tx -> getConfirmations(tx) } /** * @return the number of confirmations, zero if the transaction is in the mempool, null if the transaction is not found diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumDataTypes.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumDataTypes.kt index ed5328672..09e70f071 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumDataTypes.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumDataTypes.kt @@ -87,15 +87,15 @@ data class GetScriptHashHistory(val scriptHash: ByteVector32) : ElectrumRequest( override val method: String = "blockchain.scripthash.get_history" } -data class TransactionHistoryItem(val blockHeight: Int, val txid: ByteVector32) +data class TransactionHistoryItem(val blockHeight: Int, val txid: TxId) data class GetScriptHashHistoryResponse(val scriptHash: ByteVector32, val history: List) : ElectrumResponse data class ScriptHashListUnspent(val scriptHash: ByteVector32) : ElectrumRequest(scriptHash) { override val method: String = "blockchain.scripthash.listunspent" } -data class UnspentItem(val txid: ByteVector32, val outputIndex: Int, val value: Long, val blockHeight: Long) { - val outPoint by lazy { OutPoint(txid.reversed(), outputIndex.toLong()) } +data class UnspentItem(val txid: TxId, val outputIndex: Int, val value: Long, val blockHeight: Long) { + val outPoint by lazy { OutPoint(txid, outputIndex.toLong()) } } data class ScriptHashListUnspentResponse(val scriptHash: ByteVector32, val unspents: List) : ElectrumResponse @@ -110,9 +110,9 @@ data class GetTransactionIdFromPosition(val blockHeight: Int, val txIndex: Int, override val method: String = "blockchain.transaction.id_from_pos" } -data class GetTransactionIdFromPositionResponse(val txid: ByteVector32, val blockHeight: Int, val txIndex: Int, val merkle: List = emptyList()) : ElectrumResponse +data class GetTransactionIdFromPositionResponse(val txid: TxId, val blockHeight: Int, val txIndex: Int, val merkleProof: List = emptyList()) : ElectrumResponse -data class GetTransaction(val txid: ByteVector32, val contextOpt: Any? = null) : ElectrumRequest(txid) { +data class GetTransaction(val txid: TxId, val contextOpt: Any? = null) : ElectrumRequest(txid) { override val method: String = "blockchain.transaction.get" } @@ -132,11 +132,11 @@ data class GetHeadersResponse(val start_height: Int, val headers: List, val block_height: Int, val pos: Int, val contextOpt: Transaction? = null) : ElectrumResponse { +data class GetMerkleResponse(val txid: TxId, val merkleProof: List, val blockHeight: Int, val pos: Int, val contextOpt: Transaction? = null) : ElectrumResponse { val root: ByteVector32 by lazy { tailrec fun loop(pos: Int, hashes: List): ByteVector32 { return if (hashes.size == 1) hashes[0] @@ -146,8 +146,7 @@ data class GetMerkleResponse(val txid: ByteVector32, val merkle: List { val jsonArray = rpcResponse.result.jsonArray val items = jsonArray.map { - val txHash = it.jsonObject.getValue("tx_hash").jsonPrimitive.content + // Electrum calls this field tx_hash but actually returns the tx_id. + val txId = TxId(it.jsonObject.getValue("tx_hash").jsonPrimitive.content) val txPos = it.jsonObject.getValue("tx_pos").jsonPrimitive.int val value = it.jsonObject.getValue("value").jsonPrimitive.long val height = it.jsonObject.getValue("height").jsonPrimitive.long - UnspentItem(ByteVector32.fromValidHex(txHash), txPos, value, height) + UnspentItem(txId, txPos, value, height) } ScriptHashListUnspentResponse(request.scriptHash, items) } is GetTransactionIdFromPosition -> { - val (txHash, leaves) = if (rpcResponse.result is JsonPrimitive) { - rpcResponse.result.content to emptyList() + val (txId, merkleProof) = if (rpcResponse.result is JsonPrimitive) { + Pair(TxId(rpcResponse.result.content), emptyList()) } else { val jsonObject = rpcResponse.result.jsonObject - jsonObject.getValue("tx_hash").jsonPrimitive.content to - jsonObject.getValue("merkle").jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) } + // Electrum calls this field tx_hash but actually returns the tx_id. + val txId = TxId(jsonObject.getValue("tx_hash").jsonPrimitive.content) + val merkleProof = jsonObject.getValue("merkle").jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) } + Pair(txId, merkleProof) } - - GetTransactionIdFromPositionResponse(ByteVector32.fromValidHex(txHash), request.blockHeight, request.txIndex, leaves) + GetTransactionIdFromPositionResponse(txId, request.blockHeight, request.txIndex, merkleProof) } is GetTransaction -> { @@ -312,15 +314,14 @@ internal fun parseJsonResponse(request: ElectrumRequest, rpcResponse: JsonRPCRes // if we got here, it means that the server's response does not contain an error and message should be our // transaction id. However, it seems that at least on testnet some servers still use an older version of the // Electrum protocol and return an error message in the result field - val result = runTrying { - ByteVector32.fromValidHex(message) + val txId = runTrying { + TxId(message) } - when (result) { + when (txId) { is Try.Success -> { - if (result.result == request.tx.txid) BroadcastTransactionResponse(request.tx) - else BroadcastTransactionResponse(request.tx, JsonRPCError(1, "response txid $result does not match request txid ${request.tx.txid}")) + if (txId.result == request.tx.txid) BroadcastTransactionResponse(request.tx) + else BroadcastTransactionResponse(request.tx, JsonRPCError(1, "response txid $txId does not match request txid ${request.tx.txid}")) } - is Try.Failure -> { BroadcastTransactionResponse(request.tx, JsonRPCError(1, message)) } @@ -356,10 +357,10 @@ internal fun parseJsonResponse(request: ElectrumRequest, rpcResponse: JsonRPCRes is GetMerkle -> { val jsonObject = rpcResponse.result.jsonObject - val leaves = jsonObject.getValue("merkle").jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) } + val merkleProof = jsonObject.getValue("merkle").jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) } val blockHeight = jsonObject.getValue("block_height").jsonPrimitive.int val pos = jsonObject.getValue("pos").jsonPrimitive.int - GetMerkleResponse(request.txid, leaves, blockHeight, pos, request.contextOpt) + GetMerkleResponse(request.txid, merkleProof, blockHeight, pos, request.contextOpt) } is EstimateFees -> { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWallet.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWallet.kt index 0974c90b7..b99f34486 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWallet.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWallet.kt @@ -15,7 +15,7 @@ import org.kodein.log.Logger import org.kodein.log.LoggerFactory import org.kodein.log.newLogger -data class WalletState(val addresses: Map>, val parentTxs: Map) { +data class WalletState(val addresses: Map>, val parentTxs: Map) { /** Electrum sends parent txs separately from utxo outpoints, this boolean indicates when the wallet is consistent */ val consistent: Boolean = addresses.flatMap { it.value }.all { parentTxs.containsKey(it.txid) } val utxos: List = addresses @@ -96,7 +96,7 @@ private sealed interface WalletCommand { * A very simple wallet that only watches one address and publishes its utxos. */ class ElectrumMiniWallet( - val chainHash: ByteVector32, + val chainHash: BlockHash, private val client: IElectrumClient, private val scope: CoroutineScope, loggerFactory: LoggerFactory, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcher.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcher.kt index a0c80bd77..d836b97ad 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcher.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcher.kt @@ -92,9 +92,9 @@ class ElectrumWatcher(val client: IElectrumClient, val scope: CoroutineScope, lo .filter { state.height - item.blockHeight + 1 >= it.minDepth } triggered.forEach { w -> client.getMerkle(w.txId, item.blockHeight)?.let { merkle -> - val confirmations = state.height - merkle.block_height + 1 - logger.info { "txid=${w.txId} had confirmations=$confirmations in block=${merkle.block_height} pos=${merkle.pos}" } - _notificationsFlow.emit(WatchEventConfirmed(w.channelId, w.event, merkle.block_height, merkle.pos, txMap[w.txId]!!)) + val confirmations = state.height - merkle.blockHeight + 1 + logger.info { "txid=${w.txId} had confirmations=$confirmations in block=${merkle.blockHeight} pos=${merkle.pos}" } + _notificationsFlow.emit(WatchEventConfirmed(w.channelId, w.event, merkle.blockHeight, merkle.pos, txMap[w.txId]!!)) // check whether we have transactions to publish when (val event = w.event) { @@ -103,7 +103,7 @@ class ElectrumWatcher(val client: IElectrumClient, val scope: CoroutineScope, lo logger.info { "parent tx of txid=${tx.txid} has been confirmed" } val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) - val absTimeout = max(merkle.block_height + csvTimeout, cltvTimeout) + val absTimeout = max(merkle.blockHeight + csvTimeout, cltvTimeout) state = if (absTimeout > state.height) { logger.info { "delaying publication of txid=${tx.txid} until block=$absTimeout (curblock=${state.height})" } val block2tx = state.block2tx + (absTimeout to state.block2tx.getOrElse(absTimeout) { setOf() } + tx) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/IElectrumClient.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/IElectrumClient.kt index 3574d3859..64cb4ac5a 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/IElectrumClient.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/IElectrumClient.kt @@ -3,6 +3,7 @@ package fr.acinq.lightning.blockchain.electrum import fr.acinq.bitcoin.BlockHeader import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.blockchain.fee.FeeratePerKw import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -13,7 +14,7 @@ interface IElectrumClient { val connectionStatus: StateFlow /** Return the transaction matching the txId provided, if it can be found. */ - suspend fun getTx(txid: ByteVector32): Transaction? + suspend fun getTx(txId: TxId): Transaction? /** Return the block header at the given height, if it exists. */ suspend fun getHeader(blockHeight: Int): BlockHeader? @@ -22,7 +23,7 @@ interface IElectrumClient { suspend fun getHeaders(startHeight: Int, count: Int): List /** Return a merkle proof for the given transaction, if it can be found. */ - suspend fun getMerkle(txid: ByteVector32, blockHeight: Int, contextOpt: Transaction? = null): GetMerkleResponse? + suspend fun getMerkle(txId: TxId, blockHeight: Int, contextOpt: Transaction? = null): GetMerkleResponse? /** Return the transaction history for a given script, or an empty list if the script is unknown. */ suspend fun getScriptHashHistory(scriptHash: ByteVector32): List @@ -34,7 +35,7 @@ interface IElectrumClient { * Try broadcasting a transaction: we cannot know whether the remote server really broadcast the transaction, * so we always consider it to be a success. The client should regularly retry transactions that don't confirm. */ - suspend fun broadcastTransaction(tx: Transaction): ByteVector32 + suspend fun broadcastTransaction(tx: Transaction): TxId /** Estimate the feerate required for a transaction to be confirmed in the next [confirmations] blocks. */ suspend fun estimateFees(confirmations: Int): FeeratePerKw? diff --git a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManager.kt b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManager.kt index ecbefa638..bdd3858fd 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManager.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManager.kt @@ -1,7 +1,7 @@ package fr.acinq.lightning.blockchain.electrum -import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.OutPoint +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.Lightning import fr.acinq.lightning.SwapInParams import fr.acinq.lightning.channel.LocalFundingStatus @@ -14,7 +14,7 @@ import fr.acinq.lightning.utils.MDCLogger import fr.acinq.lightning.utils.sat internal sealed class SwapInCommand { - data class TrySwapIn(val currentBlockHeight: Int, val wallet: WalletState, val swapInParams: SwapInParams, val trustedTxs: Set) : SwapInCommand() + data class TrySwapIn(val currentBlockHeight: Int, val wallet: WalletState, val swapInParams: SwapInParams, val trustedTxs: Set) : SwapInCommand() data class UnlockWalletInputs(val inputs: Set) : SwapInCommand() } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt index bceb4c1da..518971e47 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt @@ -72,24 +72,24 @@ sealed class ChannelAction { data class RemoveChannel(val data: PersistedChannelState) : Storage() data class HtlcInfo(val channelId: ByteVector32, val commitmentNumber: Long, val paymentHash: ByteVector32, val cltvExpiry: CltvExpiry) data class StoreHtlcInfos(val htlcs: List) : Storage() - data class GetHtlcInfos(val revokedCommitTxId: ByteVector32, val commitmentNumber: Long) : Storage() + data class GetHtlcInfos(val revokedCommitTxId: TxId, val commitmentNumber: Long) : Storage() /** Payment received through on-chain operations (channel creation or splice-in) */ sealed class StoreIncomingPayment : Storage() { abstract val origin: Origin? - abstract val txId: ByteVector32 + abstract val txId: TxId abstract val localInputs: Set - data class ViaNewChannel(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: ByteVector32, override val origin: Origin?) : StoreIncomingPayment() - data class ViaSpliceIn(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: ByteVector32, override val origin: Origin.PayToOpenOrigin?) : StoreIncomingPayment() + data class ViaNewChannel(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin?) : StoreIncomingPayment() + data class ViaSpliceIn(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin.PayToOpenOrigin?) : StoreIncomingPayment() } /** Payment sent through on-chain operations (channel close or splice-out) */ sealed class StoreOutgoingPayment : Storage() { abstract val miningFees: Satoshi - abstract val txId: ByteVector32 - data class ViaSpliceOut(val amount: Satoshi, override val miningFees: Satoshi, val address: String, override val txId: ByteVector32) : StoreOutgoingPayment() - data class ViaSpliceCpfp(override val miningFees: Satoshi, override val txId: ByteVector32) : StoreOutgoingPayment() - data class ViaClose(val amount: Satoshi, override val miningFees: Satoshi, val address: String, override val txId: ByteVector32, val isSentToDefaultAddress: Boolean, val closingType: ChannelClosingType) : StoreOutgoingPayment() + abstract val txId: TxId + data class ViaSpliceOut(val amount: Satoshi, override val miningFees: Satoshi, val address: String, override val txId: TxId) : StoreOutgoingPayment() + data class ViaSpliceCpfp(override val miningFees: Satoshi, override val txId: TxId) : StoreOutgoingPayment() + data class ViaClose(val amount: Satoshi, override val miningFees: Satoshi, val address: String, override val txId: TxId, val isSentToDefaultAddress: Boolean, val closingType: ChannelClosingType) : StoreOutgoingPayment() } - data class SetLocked(val txId: ByteVector32) : Storage() + data class SetLocked(val txId: TxId) : Storage() } data class ProcessIncomingHtlc(val add: UpdateAddHtlc) : ChannelAction() diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelCommand.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelCommand.kt index ec278224f..5791eb484 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelCommand.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelCommand.kt @@ -1,9 +1,6 @@ package fr.acinq.lightning.channel -import fr.acinq.bitcoin.ByteVector -import fr.acinq.bitcoin.ByteVector32 -import fr.acinq.bitcoin.Satoshi -import fr.acinq.bitcoin.TxOut +import fr.acinq.bitcoin.* import fr.acinq.lightning.CltvExpiry import fr.acinq.lightning.MilliSatoshi import fr.acinq.lightning.blockchain.WatchEvent @@ -102,7 +99,7 @@ sealed class ChannelCommand { data class Created( val channelId: ByteVector32, val fundingTxIndex: Long, - val fundingTxId: ByteVector32, + val fundingTxId: TxId, val capacity: Satoshi, val balance: MilliSatoshi ) : Response() @@ -129,7 +126,7 @@ sealed class ChannelCommand { } sealed class Closing : ChannelCommand() { - data class GetHtlcInfosResponse(val revokedCommitTxId: ByteVector32, val htlcInfos: List) : Closing() + data class GetHtlcInfosResponse(val revokedCommitTxId: TxId, val htlcInfos: List) : Closing() } // @formatter:on } \ No newline at end of file diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelException.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelException.kt index ae2fa44a7..970ce5967 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelException.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelException.kt @@ -1,7 +1,9 @@ package fr.acinq.lightning.channel +import fr.acinq.bitcoin.BlockHash import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.Satoshi +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.CltvExpiry import fr.acinq.lightning.CltvExpiryDelta import fr.acinq.lightning.MilliSatoshi @@ -14,7 +16,7 @@ open class ChannelException(open val channelId: ByteVector32, override val messa } // @formatter:off -data class InvalidChainHash (override val channelId: ByteVector32, val local: ByteVector32, val remote: ByteVector32) : ChannelException(channelId, "invalid chainHash (local=$local remote=$remote)") +data class InvalidChainHash (override val channelId: ByteVector32, val local: BlockHash, val remote: BlockHash) : ChannelException(channelId, "invalid chainHash (local=$local remote=$remote)") data class InvalidFundingAmount (override val channelId: ByteVector32, val fundingAmount: Satoshi) : ChannelException(channelId, "invalid funding_amount=$fundingAmount") data class InvalidPushAmount (override val channelId: ByteVector32, val pushAmount: MilliSatoshi, val max: MilliSatoshi) : ChannelException(channelId, "invalid pushAmount=$pushAmount (max=$max)") data class InvalidMaxAcceptedHtlcs (override val channelId: ByteVector32, val maxAcceptedHtlcs: Int, val max: Int) : ChannelException(channelId, "invalid max_accepted_htlcs=$maxAcceptedHtlcs (max=$max)") @@ -30,11 +32,11 @@ data class DualFundingAborted (override val channelId: Byte data class UnexpectedInteractiveTxMessage (override val channelId: ByteVector32, val msg: InteractiveTxMessage) : ChannelException(channelId, "unexpected interactive-tx message (${msg::class})") data class UnexpectedCommitSig (override val channelId: ByteVector32) : ChannelException(channelId, "unexpected commitment signatures (commit_sig)") data class UnexpectedFundingSignatures (override val channelId: ByteVector32) : ChannelException(channelId, "unexpected funding signatures (tx_signatures)") -data class InvalidFundingSignature (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "invalid funding signature: txId=$txId") +data class InvalidFundingSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid funding signature: txId=$txId") data class InvalidRbfFeerate (override val channelId: ByteVector32, val proposed: FeeratePerKw, val expected: FeeratePerKw) : ChannelException(channelId, "invalid rbf attempt: the feerate must be at least $expected, you proposed $proposed") data class InvalidRbfAlreadyInProgress (override val channelId: ByteVector32) : ChannelException(channelId, "invalid rbf attempt: the current rbf attempt must be completed or aborted first") data class InvalidRbfTxAbortNotAcked (override val channelId: ByteVector32) : ChannelException(channelId, "invalid rbf attempt: our previous tx_abort has not been acked") -data class InvalidRbfTxConfirmed (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "no need to rbf, transaction is already confirmed with txId=$txId") +data class InvalidRbfTxConfirmed (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "no need to rbf, transaction is already confirmed with txId=$txId") data class InvalidRbfNonInitiator (override val channelId: ByteVector32) : ChannelException(channelId, "cannot initiate rbf: we're not the initiator of this interactive-tx attempt") data class InvalidRbfAttempt (override val channelId: ByteVector32) : ChannelException(channelId, "invalid rbf attempt") data class InvalidSpliceAlreadyInProgress (override val channelId: ByteVector32) : ChannelException(channelId, "invalid splice attempt: the current splice attempt must be completed or aborted first") @@ -46,16 +48,16 @@ data class CannotCloseWithUnsignedOutgoingHtlcs (override val channelId: Byte data class CannotCloseWithUnsignedOutgoingUpdateFee(override val channelId: ByteVector32) : ChannelException(channelId, "cannot close when there is an unsigned fee update") data class ChannelUnavailable (override val channelId: ByteVector32) : ChannelException(channelId, "channel is unavailable (offline or closing)") data class InvalidFinalScript (override val channelId: ByteVector32) : ChannelException(channelId, "invalid final script") -data class FundingTxSpent (override val channelId: ByteVector32, val spendingTxId: ByteVector32) : ChannelException(channelId, "funding tx has been spent by txId=$spendingTxId") +data class FundingTxSpent (override val channelId: ByteVector32, val spendingTxId: TxId) : ChannelException(channelId, "funding tx has been spent by txId=$spendingTxId") data class HtlcsTimedOutDownstream (override val channelId: ByteVector32, val htlcs: Set) : ChannelException(channelId, "one or more htlcs timed out downstream: ids=${htlcs.map { it.id } .joinToString(",")}") data class FulfilledHtlcsWillTimeout (override val channelId: ByteVector32, val htlcs: Set) : ChannelException(channelId, "one or more htlcs that should be fulfilled are close to timing out: ids=${htlcs.map { it.id }.joinToString()}") data class HtlcOverriddenByLocalCommit (override val channelId: ByteVector32, val htlc: UpdateAddHtlc) : ChannelException(channelId, "htlc ${htlc.id} was overridden by local commit") data class FeerateTooSmall (override val channelId: ByteVector32, val remoteFeeratePerKw: FeeratePerKw) : ChannelException(channelId, "remote fee rate is too small: remoteFeeratePerKw=${remoteFeeratePerKw.toLong()}") data class FeerateTooDifferent (override val channelId: ByteVector32, val localFeeratePerKw: FeeratePerKw, val remoteFeeratePerKw: FeeratePerKw) : ChannelException(channelId, "local/remote feerates are too different: remoteFeeratePerKw=${remoteFeeratePerKw.toLong()} localFeeratePerKw=${localFeeratePerKw.toLong()}") -data class InvalidCommitmentSignature (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "invalid commitment signature: txId=$txId") -data class InvalidHtlcSignature (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "invalid htlc signature: txId=$txId") -data class InvalidCloseSignature (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "invalid close signature: txId=$txId") -data class InvalidCloseAmountBelowDust (override val channelId: ByteVector32, val txId: ByteVector32) : ChannelException(channelId, "invalid closing tx: some outputs are below dust: txId=$txId") +data class InvalidCommitmentSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid commitment signature: txId=$txId") +data class InvalidHtlcSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid htlc signature: txId=$txId") +data class InvalidCloseSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid close signature: txId=$txId") +data class InvalidCloseAmountBelowDust (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid closing tx: some outputs are below dust: txId=$txId") data class CommitSigCountMismatch (override val channelId: ByteVector32, val expected: Int, val actual: Int) : ChannelException(channelId, "commit sig count mismatch: expected=$expected actual=$actual") data class SwapInSigCountMismatch (override val channelId: ByteVector32, val expected: Int, val actual: Int) : ChannelException(channelId, "swap-in sig count mismatch: expected=$expected actual=$actual") data class HtlcSigCountMismatch (override val channelId: ByteVector32, val expected: Int, val actual: Int) : ChannelException(channelId, "htlc sig count mismatch: expected=$expected actual: $actual") diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt index 1408bbb26..ea59a9f2e 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt @@ -95,9 +95,19 @@ data class PublishableTxs(val commitTx: CommitTx, val htlcTxsAndSigs: List { // remote commitment will include all local changes + remote acked changes val spec = CommitmentSpec.reduce(remoteCommit.spec, changes.remoteChanges.acked, changes.localChanges.proposed) - val (remoteCommitTx, htlcTxs) = Commitments.makeRemoteTxs(channelKeys, commitTxNumber = remoteCommit.index + 1, params.localParams, params.remoteParams, fundingTxIndex = fundingTxIndex, remoteFundingPubKey = remoteFundingPubkey, commitInput, remotePerCommitmentPoint = remoteNextPerCommitmentPoint, spec) + val (remoteCommitTx, htlcTxs) = Commitments.makeRemoteTxs( + channelKeys, + commitTxNumber = remoteCommit.index + 1, + params.localParams, + params.remoteParams, + fundingTxIndex = fundingTxIndex, + remoteFundingPubKey = remoteFundingPubkey, + commitInput, + remotePerCommitmentPoint = remoteNextPerCommitmentPoint, + spec + ) val sig = Transactions.sign(remoteCommitTx, channelKeys.fundingKey(fundingTxIndex)) val sortedHtlcTxs: List = htlcTxs.sortedBy { it.input.outPoint.index } @@ -434,7 +454,17 @@ data class Commitment( // receiving money i.e its commit tx has one output for them val spec = CommitmentSpec.reduce(localCommit.spec, changes.localChanges.acked, changes.remoteChanges.proposed) val localPerCommitmentPoint = channelKeys.commitmentPoint(localCommit.index + 1) - val (localCommitTx, htlcTxs) = Commitments.makeLocalTxs(channelKeys, commitTxNumber = localCommit.index + 1, params.localParams, params.remoteParams, fundingTxIndex = fundingTxIndex, remoteFundingPubKey = remoteFundingPubkey, commitInput, localPerCommitmentPoint = localPerCommitmentPoint, spec) + val (localCommitTx, htlcTxs) = Commitments.makeLocalTxs( + channelKeys, + commitTxNumber = localCommit.index + 1, + params.localParams, + params.remoteParams, + fundingTxIndex = fundingTxIndex, + remoteFundingPubKey = remoteFundingPubkey, + commitInput, + localPerCommitmentPoint = localPerCommitmentPoint, + spec + ) val sig = Transactions.sign(localCommitTx, channelKeys.fundingKey(fundingTxIndex)) log.info { @@ -493,7 +523,7 @@ data class FullCommitment( ) { val channelId = params.channelId val commitInput = localCommit.publishableTxs.commitTx.input - val fundingTxId: ByteVector32 = commitInput.outPoint.txid + val fundingTxId: TxId = commitInput.outPoint.txid val fundingAmount = commitInput.txOut.amount val localChannelReserve = when { params.channelFeatures.hasFeature(Feature.ZeroReserveChannels) && !params.localParams.isInitiator -> 0.sat @@ -534,7 +564,7 @@ data class Commitments( fun availableBalanceForReceive(): MilliSatoshi = active.minOf { it.availableBalanceForReceive(params, changes) } // We always use the last commitment that was created, to make sure we never go back in time. - val latest = FullCommitment(params, changes, active.first().fundingTxIndex, active.first().remoteFundingPubkey, active.first().localFundingStatus, active.first().remoteFundingStatus, active.first().localCommit, active.first().remoteCommit, active.first().nextRemoteCommit) + val latest = active.first().let { c -> FullCommitment(params, changes, c.fundingTxIndex, c.remoteFundingPubkey, c.localFundingStatus, c.remoteFundingStatus, c.localCommit, c.remoteCommit, c.nextRemoteCommit) } val all = buildList { addAll(active) @@ -794,7 +824,7 @@ data class Commitments( return Either.Right(Pair(commitments1, actions.toList())) } - private fun ChannelContext.updateFundingStatus(fundingTxId: ByteVector32, updateMethod: (Commitment, Long) -> Commitment): Either> { + private fun ChannelContext.updateFundingStatus(fundingTxId: TxId, updateMethod: (Commitment, Long) -> Commitment): Either> { return when (val c = all.find { it.fundingTxId == fundingTxId }) { is Commitment -> { val commitments1 = copy( @@ -839,7 +869,7 @@ data class Commitments( } else c } - fun ChannelContext.updateRemoteFundingStatus(fundingTxId: ByteVector32): Either> = + fun ChannelContext.updateRemoteFundingStatus(fundingTxId: TxId): Either> = updateFundingStatus(fundingTxId) { c: Commitment, fundingTxIndex: Long -> // all funding older than this one are considered locked if (c.fundingTxId == fundingTxId || c.fundingTxIndex < fundingTxIndex) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/Helpers.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/Helpers.kt index eba01af52..73c70f532 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/Helpers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/Helpers.kt @@ -258,7 +258,7 @@ object Helpers { } fun makeFundingInputInfo( - fundingTxId: ByteVector32, + fundingTxId: TxId, fundingTxOutputIndex: Int, fundingAmount: Satoshi, fundingPubkey1: PublicKey, @@ -292,7 +292,7 @@ object Helpers { remoteCommitmentIndex: Long, commitTxFeerate: FeeratePerKw, fundingTxIndex: Long, - fundingTxHash: ByteVector32, + fundingTxId: TxId, fundingTxOutputIndex: Int, remoteFundingPubkey: PublicKey, remotePerCommitmentPoint: PublicKey @@ -313,7 +313,7 @@ object Helpers { } val fundingPubKey = channelKeys.fundingPubKey(fundingTxIndex) - val commitmentInput = makeFundingInputInfo(fundingTxHash, fundingTxOutputIndex, fundingAmount, fundingPubKey, remoteFundingPubkey) + val commitmentInput = makeFundingInputInfo(fundingTxId, fundingTxOutputIndex, fundingAmount, fundingPubKey, remoteFundingPubkey) val localPerCommitmentPoint = channelKeys.commitmentPoint(localCommitmentIndex) val localCommitTx = Commitments.makeLocalTxs( channelKeys, @@ -364,48 +364,6 @@ object Helpers { fun isValidFinalScriptPubkey(scriptPubKey: ByteVector, allowAnySegwit: Boolean): Boolean = isValidFinalScriptPubkey(scriptPubKey.toByteArray(), allowAnySegwit) - // To be replaced with corresponding function in bitcoin-kmp - fun btcAddressFromScriptPubKey(scriptPubKey: ByteVector, chainHash: ByteVector32): String? { - return runTrying { - val script = Script.parse(scriptPubKey) - when { - Script.isPay2pkh(script) -> { - // OP_DUP OP_HASH160 OP_PUSHDATA(20) OP_EQUALVERIFY OP_CHECKSIG - val opPushData = script[2] as OP_PUSHDATA - val prefix = when (chainHash) { - Block.LivenetGenesisBlock.hash -> Base58.Prefix.PubkeyAddress - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash -> Base58.Prefix.PubkeyAddressTestnet - else -> null - } ?: return null - Base58Check.encode(prefix, opPushData.data) - } - Script.isPay2sh(script) -> { - // OP_HASH160 OP_PUSHDATA(20) OP_EQUAL - val opPushData = script[1] as OP_PUSHDATA - val prefix = when (chainHash) { - Block.LivenetGenesisBlock.hash -> Base58.Prefix.ScriptAddress - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash -> Base58.Prefix.ScriptAddressTestnet - else -> null - } ?: return null - Base58Check.encode(prefix, opPushData.data) - } - Script.isPay2wpkh(script) || Script.isPay2wsh(script) -> { - // isPay2wpkh : OP_0 OP_PUSHDATA(20) - // isPay2wsh : OP_0 OP_PUSHDATA(32) - val opPushData = script[1] as OP_PUSHDATA - val hrp = when (chainHash) { - Block.LivenetGenesisBlock.hash -> "bc" - Block.TestnetGenesisBlock.hash -> "tb" - Block.RegtestGenesisBlock.hash -> "bcrt" - else -> null - } ?: return null - Bech32.encodeWitnessAddress(hrp, 0, opPushData.data.toByteArray()) - } - else -> null - } // - }.getOrElse { null } - } - private fun firstClosingFee(commitment: FullCommitment, localScriptPubkey: ByteArray, remoteScriptPubkey: ByteArray, requestedFeerate: ClosingFeerates): ClosingFees { // this is just to estimate the weight which depends on the size of the pubkey scripts val dummyClosingTx = Transactions.makeClosingTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.params.localParams.isInitiator, Satoshi(0), Satoshi(0), commitment.localCommit.spec) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt index 3b0086c74..2703e9789 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt @@ -163,8 +163,8 @@ sealed class InteractiveTxOutput { sealed class FundingContributionFailure { // @formatter:off - data class InputOutOfBounds(val txId: ByteVector32, val outputIndex: Int) : FundingContributionFailure() { override fun toString(): String = "invalid input $txId:$outputIndex (out of bounds)" } - data class InputBelowDust(val txId: ByteVector32, val outputIndex: Int, val amount: Satoshi, val dustLimit: Satoshi) : FundingContributionFailure() { override fun toString(): String = "invalid input $txId:$outputIndex (below dust: amount=$amount, dust=$dustLimit)" } + data class InputOutOfBounds(val txId: TxId, val outputIndex: Int) : FundingContributionFailure() { override fun toString(): String = "invalid input $txId:$outputIndex (out of bounds)" } + data class InputBelowDust(val txId: TxId, val outputIndex: Int, val amount: Satoshi, val dustLimit: Satoshi) : FundingContributionFailure() { override fun toString(): String = "invalid input $txId:$outputIndex (below dust: amount=$amount, dust=$dustLimit)" } data class InputTxTooLarge(val tx: Transaction) : FundingContributionFailure() { override fun toString(): String = "invalid input tx ${tx.txid} (too large)" } data class NotEnoughFunding(val fundingAmount: Satoshi, val nonFundingAmount: Satoshi, val providedAmount: Satoshi) : FundingContributionFailure() { override fun toString(): String = "not enough funds provided (expected at least $fundingAmount + $nonFundingAmount, got $providedAmount)" } data class NotEnoughFees(val currentFees: Satoshi, val expectedFees: Satoshi) : FundingContributionFailure() { override fun toString(): String = "not enough funds to pay fees (expected at least $expectedFees, got $currentFees)" } @@ -362,14 +362,14 @@ data class SharedTransaction( /** Signed transaction created collaboratively. */ sealed class SignedSharedTransaction { - abstract val txId: ByteVector32 + abstract val txId: TxId abstract val tx: SharedTransaction abstract val localSigs: TxSignatures abstract val signedTx: Transaction? } data class PartiallySignedSharedTransaction(override val tx: SharedTransaction, override val localSigs: TxSignatures) : SignedSharedTransaction() { - override val txId: ByteVector32 = localSigs.txId + override val txId: TxId = localSigs.txId override val signedTx = null fun addRemoteSigs(channelKeys: KeyManager.ChannelKeys, fundingParams: InteractiveTxParams, remoteSigs: TxSignatures): FullySignedSharedTransaction? { @@ -422,7 +422,7 @@ data class FullySignedSharedTransaction(override val tx: SharedTransaction, over val outputs = (sharedTxOut + localTxOut + remoteTxOut).sortedBy { (serialId, _) -> serialId }.map { (_, o) -> o } Transaction(2, inputs, outputs, tx.lockTime) } - override val txId: ByteVector32 = signedTx.txid + override val txId: TxId = signedTx.txid val feerate: FeeratePerKw = Transactions.fee2rate(tx.fees, signedTx.weight()) } @@ -435,10 +435,10 @@ sealed class InteractiveTxSessionAction { data class UnknownSerialId(val channelId: ByteVector32, val serialId: Long) : RemoteFailure() { override fun toString(): String = "unknown serial_id=$serialId" } data class TooManyInteractiveTxRounds(val channelId: ByteVector32) : RemoteFailure() { override fun toString(): String = "too many messages exchanged during interactive tx construction" } data class DuplicateSerialId(val channelId: ByteVector32, val serialId: Long) : RemoteFailure() { override fun toString(): String = "duplicate serial_id=$serialId" } - data class DuplicateInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: ByteVector32, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "duplicate input $previousTxId:$previousTxOutput (serial_id=$serialId)" } - data class InputOutOfBounds(val channelId: ByteVector32, val serialId: Long, val previousTxId: ByteVector32, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "invalid input $previousTxId:$previousTxOutput (serial_id=$serialId)" } - data class NonReplaceableInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: ByteVector32, val previousTxOutput: Long, val sequence: Long) : RemoteFailure() { override fun toString(): String = "$previousTxId:$previousTxOutput is not replaceable (serial_id=$serialId, nSequence=$sequence)" } - data class NonSegwitInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: ByteVector32, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "$previousTxId:$previousTxOutput is not a native segwit input (serial_id=$serialId)" } + data class DuplicateInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: TxId, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "duplicate input $previousTxId:$previousTxOutput (serial_id=$serialId)" } + data class InputOutOfBounds(val channelId: ByteVector32, val serialId: Long, val previousTxId: TxId, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "invalid input $previousTxId:$previousTxOutput (serial_id=$serialId)" } + data class NonReplaceableInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: TxId, val previousTxOutput: Long, val sequence: Long) : RemoteFailure() { override fun toString(): String = "$previousTxId:$previousTxOutput is not replaceable (serial_id=$serialId, nSequence=$sequence)" } + data class NonSegwitInput(val channelId: ByteVector32, val serialId: Long, val previousTxId: TxId, val previousTxOutput: Long) : RemoteFailure() { override fun toString(): String = "$previousTxId:$previousTxOutput is not a native segwit input (serial_id=$serialId)" } data class PreviousTxMissing(val channelId: ByteVector32, val serialId: Long) : RemoteFailure() { override fun toString(): String = "previous tx missing from tx_add_input (serial_id=$serialId)" } data class InvalidSharedInput(val channelId: ByteVector32, val serialId: Long) : RemoteFailure() { override fun toString(): String = "invalid shared tx_add_input (serial_id=$serialId)" } data class OutputBelowDust(val channelId: ByteVector32, val serialId: Long, val amount: Satoshi, val dustLimit: Satoshi) : RemoteFailure() { override fun toString(): String = "invalid output amount=$amount below dust=$dustLimit (serial_id=$serialId)" } @@ -447,10 +447,10 @@ sealed class InteractiveTxSessionAction { data class InvalidTxSharedInput(val channelId: ByteVector32) : RemoteFailure() { override fun toString(): String = "shared input is missing or duplicated" } data class InvalidTxSharedOutput(val channelId: ByteVector32) : RemoteFailure() { override fun toString(): String = "shared output is missing or duplicated" } data class InvalidTxSharedAmount(val channelId: ByteVector32, val serialId: Long, val amount: Satoshi, val expected: Satoshi) : RemoteFailure() { override fun toString(): String = "invalid shared output amount=$amount expected=$expected (serial_id=$serialId)" } - data class InvalidTxChangeAmount(val channelId: ByteVector32, val txId: ByteVector32) : RemoteFailure() { override fun toString(): String = "change amount is too high (txId=$txId)" } - data class InvalidTxWeight(val channelId: ByteVector32, val txId: ByteVector32) : RemoteFailure() { override fun toString(): String = "transaction weight is too big for standardness rules (txId=$txId)" } - data class InvalidTxFeerate(val channelId: ByteVector32, val txId: ByteVector32, val targetFeerate: FeeratePerKw, val actualFeerate: FeeratePerKw) : RemoteFailure() { override fun toString(): String = "transaction feerate too low (txId=$txId, targetFeerate=$targetFeerate, actualFeerate=$actualFeerate" } - data class InvalidTxDoesNotDoubleSpendPreviousTx(val channelId: ByteVector32, val txId: ByteVector32, val previousTxId: ByteVector32) : RemoteFailure() { override fun toString(): String = "transaction replacement with txId=$txId doesn't double-spend previous attempt (txId=$previousTxId)" } + data class InvalidTxChangeAmount(val channelId: ByteVector32, val txId: TxId) : RemoteFailure() { override fun toString(): String = "change amount is too high (txId=$txId)" } + data class InvalidTxWeight(val channelId: ByteVector32, val txId: TxId) : RemoteFailure() { override fun toString(): String = "transaction weight is too big for standardness rules (txId=$txId)" } + data class InvalidTxFeerate(val channelId: ByteVector32, val txId: TxId, val targetFeerate: FeeratePerKw, val actualFeerate: FeeratePerKw) : RemoteFailure() { override fun toString(): String = "transaction feerate too low (txId=$txId, targetFeerate=$targetFeerate, actualFeerate=$actualFeerate" } + data class InvalidTxDoesNotDoubleSpendPreviousTx(val channelId: ByteVector32, val txId: TxId, val previousTxId: TxId) : RemoteFailure() { override fun toString(): String = "transaction replacement with txId=$txId doesn't double-spend previous attempt (txId=$previousTxId)" } // @formatter:on } @@ -843,7 +843,7 @@ data class InteractiveTxSigningSession( localCommitmentIndex = localCommitmentIndex, remoteCommitmentIndex = remoteCommitmentIndex, commitTxFeerate, - fundingTxIndex = fundingTxIndex, fundingTxHash = unsignedTx.hash, fundingTxOutputIndex = sharedOutputIndex, + fundingTxIndex = fundingTxIndex, fundingTxId = unsignedTx.txid, fundingTxOutputIndex = sharedOutputIndex, remoteFundingPubkey = fundingParams.remoteFundingPubkey, remotePerCommitmentPoint = remotePerCommitmentPoint ).map { firstCommitTx -> diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt index a58b20c48..e1234326f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt @@ -93,12 +93,7 @@ sealed class ChannelState { // this code is only executed for the first transition to Closing, so there can only be one transaction here val closingTx = newState.mutualClosePublished.first() val finalAmount = closingTx.toLocalOutput?.amount ?: 0.sat - val address = closingTx.toLocalOutput?.publicKeyScript?.let { - Helpers.Closing.btcAddressFromScriptPubKey( - scriptPubKey = it, - chainHash = staticParams.nodeParams.chainHash - ) - } ?: "unknown" + val address = closingTx.toLocalOutput?.publicKeyScript?.let { Bitcoin.addressFromPublicKeyScript(staticParams.nodeParams.chainHash, it.toByteArray()).result } ?: "unknown" listOf( ChannelAction.Storage.StoreOutgoingPayment.ViaClose( amount = finalAmount, @@ -124,10 +119,10 @@ sealed class ChannelState { Pair(revokedCommitPublished.commitTx, ChannelClosingType.Revoked) } } - val address = Helpers.Closing.btcAddressFromScriptPubKey( - scriptPubKey = oldState.commitments.params.localParams.defaultFinalScriptPubKey, // force close always send to the default script - chainHash = staticParams.nodeParams.chainHash - ) ?: "unknown" + val address = Bitcoin.addressFromPublicKeyScript( + chainHash = staticParams.nodeParams.chainHash, + pubkeyScript = oldState.commitments.params.localParams.defaultFinalScriptPubKey.toByteArray() // force close always send to the default script + ).result ?: "unknown" listOf( ChannelAction.Storage.StoreOutgoingPayment.ViaClose( amount = channelBalance.truncateToSatoshi(), @@ -286,7 +281,7 @@ sealed class PersistedChannelState : ChannelState() { nextRemoteRevocationNumber = 0, yourLastCommitmentSecret = PrivateKey(ByteVector32.Zeroes), myCurrentPerCommitmentPoint = myFirstPerCommitmentPoint, - TlvStream(ChannelReestablishTlv.NextFunding(state.signingSession.fundingTx.txId.reversed())) + TlvStream(ChannelReestablishTlv.NextFunding(state.signingSession.fundingTx.txId)) ).withChannelData(state.remoteChannelData, logger) } is ChannelStateWithCommitments -> { @@ -297,7 +292,7 @@ sealed class PersistedChannelState : ChannelState() { is Normal -> state.getUnsignedFundingTxId() // a splice was in progress, we tell our peer that we are remembering it and are expecting signatures else -> null } - val tlvs: TlvStream = unsignedFundingTxId?.let { TlvStream(ChannelReestablishTlv.NextFunding(it.reversed())) } ?: TlvStream.empty() + val tlvs: TlvStream = unsignedFundingTxId?.let { TlvStream(ChannelReestablishTlv.NextFunding(it)) } ?: TlvStream.empty() ChannelReestablish( channelId = channelId, nextLocalCommitmentNumber = state.commitments.localCommitIndex + 1, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt index 739fe3c0d..c1bd3e3d8 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt @@ -1,7 +1,8 @@ package fr.acinq.lightning.channel.states -import fr.acinq.bitcoin.ByteVector32 +import fr.acinq.bitcoin.Bitcoin import fr.acinq.bitcoin.SigHash +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.Feature import fr.acinq.lightning.Features import fr.acinq.lightning.ShortChannelId @@ -636,7 +637,7 @@ data class Normal( val (nextState, actions) = updateFundingTxStatus(watch) if (!staticParams.useZeroConf && nextState.commitments.active.any { it.fundingTxId == watch.tx.txid && it.fundingTxIndex > 0 }) { // We're not using 0-conf and a splice transaction is confirmed, so we send splice_locked. - val spliceLocked = SpliceLocked(channelId, watch.tx.hash) + val spliceLocked = SpliceLocked(channelId, watch.tx.txid) Pair(nextState, actions + ChannelAction.Message.Send(spliceLocked)) } else { Pair(nextState, actions) @@ -715,7 +716,7 @@ data class Normal( ChannelAction.Storage.StoreOutgoingPayment.ViaSpliceOut( amount = txOut.amount, miningFees = action.fundingTx.sharedTx.tx.fees, - address = Helpers.Closing.btcAddressFromScriptPubKey(scriptPubKey = txOut.publicKeyScript, chainHash = staticParams.nodeParams.chainHash) ?: "unknown", + address = Bitcoin.addressFromPublicKeyScript(staticParams.nodeParams.chainHash, txOut.publicKeyScript.toByteArray()).result ?: "unknown", txId = action.fundingTx.txId ) }) @@ -728,7 +729,7 @@ data class Normal( ) if (staticParams.useZeroConf) { logger.info { "channel is using 0-conf, sending splice_locked right away" } - val spliceLocked = SpliceLocked(channelId, action.fundingTx.txId.reversed()) + val spliceLocked = SpliceLocked(channelId, action.fundingTx.txId) add(ChannelAction.Message.Send(spliceLocked)) } } @@ -745,7 +746,7 @@ data class Normal( } /** If we haven't completed the signing steps of an interactive-tx session, we will ask our peer to retransmit signatures for the corresponding transaction. */ - fun getUnsignedFundingTxId(): ByteVector32? = when { + fun getUnsignedFundingTxId(): TxId? = when { spliceStatus is SpliceStatus.WaitingForSigs -> spliceStatus.session.fundingTx.txId commitments.latest.localFundingStatus is LocalFundingStatus.UnconfirmedFundingTx && commitments.latest.localFundingStatus.sharedTx is PartiallySignedSharedTransaction -> commitments.latest.localFundingStatus.txId else -> null diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt index a3bec493f..d7e0be35f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt @@ -216,7 +216,7 @@ data class Syncing(val state: PersistedChannelState, val channelReestablishSent: .firstOrNull { staticParams.useZeroConf || it.localFundingStatus is LocalFundingStatus.ConfirmedFundingTx } ?.let { logger.debug { "re-sending splice_locked for fundingTxId=${it.fundingTxId}" } - val spliceLocked = SpliceLocked(channelId, it.fundingTxId.reversed()) + val spliceLocked = SpliceLocked(channelId, it.fundingTxId) actions.add(ChannelAction.Message.Send(spliceLocked)) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt index f53af97c7..16e4efe62 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt @@ -1,6 +1,6 @@ package fr.acinq.lightning.channel.states -import fr.acinq.bitcoin.ByteVector32 +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.MilliSatoshi import fr.acinq.lightning.ShortChannelId import fr.acinq.lightning.blockchain.BITCOIN_FUNDING_DEPTHOK @@ -331,7 +331,7 @@ data class WaitForFundingConfirmed( } /** If we haven't completed the signing steps of an interactive-tx session, we will ask our peer to retransmit signatures for the corresponding transaction. */ - fun getUnsignedFundingTxId(): ByteVector32? { + fun getUnsignedFundingTxId(): TxId? { return when (rbfStatus) { is RbfStatus.WaitingForSigs -> rbfStatus.session.fundingTx.txId else -> when (latestFundingTx.sharedTx) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt index 8e66a48b1..b40fb13d6 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt @@ -133,7 +133,7 @@ data class WaitForFundingSigned( // We use part of the funding txid to create a dummy short channel id. // This gives us a probability of collisions of 0.1% for 5 0-conf channels and 1% for 20 // Collisions mean that users may temporarily see incorrect numbers for their 0-conf channels (until they've been confirmed). - val shortChannelId = ShortChannelId(0, Pack.int32BE(action.commitment.fundingTxId.slice(0, 16).toByteArray()).absoluteValue, action.commitment.commitInput.outPoint.index.toInt()) + val shortChannelId = ShortChannelId(0, Pack.int32BE(action.commitment.fundingTxId.value.slice(0, 16).toByteArray()).absoluteValue, action.commitment.commitInput.outPoint.index.toInt()) val nextState = WaitForChannelReady(commitments, shortChannelId, channelReady) val actions = buildList { add(ChannelAction.Storage.StoreState(nextState)) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt b/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt index c5041e35c..c453ffb19 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt @@ -29,7 +29,7 @@ interface PaymentsDb : IncomingPaymentsDb, OutgoingPaymentsDb { * the transaction is not yet confirmed. In the case of a force-close, the outgoing payment will only be considered confirmed * when the channel is closed, meaning that all related transactions have been confirmed. */ - suspend fun setLocked(txId: ByteVector32) + suspend fun setLocked(txId: TxId) } interface IncomingPaymentsDb { @@ -154,7 +154,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r data class SwapIn(val address: String?) : Origin() /** Trustless swap-in (dual-funding or splice-in) */ - data class OnChain(val txid: ByteVector32, val localInputs: Set) : Origin() + data class OnChain(val txId: TxId, val localInputs: Set) : Origin() } data class Received(val receivedWith: List, val receivedAt: Long = currentTimestampMillis()) { @@ -180,10 +180,9 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r sealed class OnChainIncomingPayment : ReceivedWith() { abstract val serviceFee: MilliSatoshi abstract val miningFee: Satoshi - override val fees: MilliSatoshi - get() = serviceFee + miningFee.toMilliSatoshi() + override val fees: MilliSatoshi get() = serviceFee + miningFee.toMilliSatoshi() abstract val channelId: ByteVector32 - abstract val txId: ByteVector32 + abstract val txId: TxId abstract val confirmedAt: Long? abstract val lockedAt: Long? } @@ -201,7 +200,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r override val serviceFee: MilliSatoshi, override val miningFee: Satoshi, override val channelId: ByteVector32, - override val txId: ByteVector32, + override val txId: TxId, override val confirmedAt: Long?, override val lockedAt: Long? ) : OnChainIncomingPayment() @@ -211,7 +210,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r override val serviceFee: MilliSatoshi, override val miningFee: Satoshi, override val channelId: ByteVector32, - override val txId: ByteVector32, + override val txId: TxId, override val confirmedAt: Long?, override val lockedAt: Long? ) : OnChainIncomingPayment() @@ -352,7 +351,7 @@ sealed class OnChainOutgoingPayment : OutgoingPayment() { abstract override val id: UUID abstract val miningFees: Satoshi abstract val channelId: ByteVector32 - abstract val txId: ByteVector32 + abstract val txId: TxId abstract override val createdAt: Long abstract val confirmedAt: Long? abstract val lockedAt: Long? @@ -364,7 +363,7 @@ data class SpliceOutgoingPayment( val address: String, override val miningFees: Satoshi, override val channelId: ByteVector32, - override val txId: ByteVector32, + override val txId: TxId, override val createdAt: Long, override val confirmedAt: Long?, override val lockedAt: Long?, @@ -378,7 +377,7 @@ data class SpliceCpfpOutgoingPayment( override val id: UUID, override val miningFees: Satoshi, override val channelId: ByteVector32, - override val txId: ByteVector32, + override val txId: TxId, override val createdAt: Long, override val confirmedAt: Long?, override val lockedAt: Long?, @@ -403,7 +402,7 @@ data class ChannelCloseOutgoingPayment( val isSentToDefaultAddress: Boolean, override val miningFees: Satoshi, override val channelId: ByteVector32, - override val txId: ByteVector32, + override val txId: TxId, override val createdAt: Long, override val confirmedAt: Long?, override val lockedAt: Long?, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt b/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt index b7ffc6f87..fb33ba2c9 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt @@ -104,7 +104,7 @@ class Peer( val db: Databases, socketBuilder: TcpSocket.Builder?, scope: CoroutineScope, - private val trustedSwapInTxs: Set = emptySet(), + private val trustedSwapInTxs: Set = emptySet(), private val initTlvStream: TlvStream = TlvStream.empty() ) : CoroutineScope by scope { companion object { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt index 563476660..577bbe0c5 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt @@ -20,8 +20,10 @@ JsonSerializers.ByteVectorSerializer::class, JsonSerializers.ByteVector32Serializer::class, JsonSerializers.ByteVector64Serializer::class, + JsonSerializers.BlockHashSerializer::class, JsonSerializers.PublicKeySerializer::class, JsonSerializers.PrivateKeySerializer::class, + JsonSerializers.TxIdSerializer::class, JsonSerializers.KeyPathSerializer::class, JsonSerializers.SatoshiSerializer::class, JsonSerializers.MilliSatoshiSerializer::class, @@ -263,7 +265,7 @@ object JsonSerializers { object SignedSharedTransactionSerializer @Serializable - data class InteractiveTxSigningSessionSurrogate(val fundingParams: InteractiveTxParams, val fundingTxId: ByteVector32) + data class InteractiveTxSigningSessionSurrogate(val fundingParams: InteractiveTxParams, val fundingTxId: TxId) object InteractiveTxSigningSessionSerializer : SurrogateSerializer( transform = { s -> InteractiveTxSigningSessionSurrogate(s.fundingParams, s.fundingTx.txId) }, delegateSerializer = InteractiveTxSigningSessionSurrogate.serializer() @@ -284,7 +286,7 @@ object JsonSerializers { object CommitmentChangesSerializer @Serializable - data class LocalFundingStatusSurrogate(val status: String, val txId: ByteVector32) + data class LocalFundingStatusSurrogate(val status: String, val txId: TxId) object LocalFundingStatusSerializer : SurrogateSerializer( transform = { o -> when (o) { @@ -357,7 +359,9 @@ object JsonSerializers { object ByteVectorSerializer : StringSerializer() object ByteVector32Serializer : StringSerializer() object ByteVector64Serializer : StringSerializer() + object BlockHashSerializer : StringSerializer() object PublicKeySerializer : StringSerializer() + object TxIdSerializer : StringSerializer() object KeyPathSerializer : StringSerializer() object ShortChannelIdSerializer : StringSerializer() object OutPointSerializer : StringSerializer({ "${it.txid}:${it.index}" }) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/payment/PaymentRequest.kt b/src/commonMain/kotlin/fr/acinq/lightning/payment/PaymentRequest.kt index 9181e4592..8bee3b7aa 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/payment/PaymentRequest.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/payment/PaymentRequest.kt @@ -128,7 +128,7 @@ data class PaymentRequest( ) fun create( - chainHash: ByteVector32, + chainHash: BlockHash, amount: MilliSatoshi?, paymentHash: ByteVector32, privateKey: PrivateKey, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/router/Announcements.kt b/src/commonMain/kotlin/fr/acinq/lightning/router/Announcements.kt index fcc3dd42f..286ac14eb 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/router/Announcements.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/router/Announcements.kt @@ -31,7 +31,7 @@ object Announcements { } fun makeChannelUpdate( - chainHash: ByteVector32, + chainHash: BlockHash, nodePrivateKey: PrivateKey, remoteNodeId: PublicKey, shortChannelId: ShortChannelId, @@ -51,7 +51,7 @@ object Announcements { } private fun channelUpdateWitnessEncode( - chainHash: ByteVector32, + chainHash: BlockHash, shortChannelId: ShortChannelId, timestampSeconds: Long, messageFlags: Byte, @@ -64,7 +64,7 @@ object Announcements { unknownFields: ByteVector ): ByteVector32 { val out = ByteArrayOutput() - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeU64(shortChannelId.toLong(), out) LightningCodecs.writeU32(timestampSeconds.toInt(), out) LightningCodecs.writeByte(messageFlags.toInt(), out) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt index 0023df36f..02aaffa19 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt @@ -4,6 +4,7 @@ EitherSerializer::class, ShaChainSerializer::class, BlockHeaderKSerializer::class, + BlockHashKSerializer::class, FundingSignedSerializer::class, ChannelUpdateSerializer::class, ByteVectorKSerializer::class, @@ -223,7 +224,7 @@ internal data class RemoteCommit( val txid: ByteVector32, val remotePerCommitmentPoint: PublicKey ) { - fun export() = fr.acinq.lightning.channel.RemoteCommit(index, spec.export(), txid, remotePerCommitmentPoint) + fun export() = fr.acinq.lightning.channel.RemoteCommit(index, spec.export(), TxId(txid), remotePerCommitmentPoint) } @Serializable @@ -404,7 +405,7 @@ internal data class Commitments( fr.acinq.lightning.channel.PartiallySignedSharedTransaction( fr.acinq.lightning.channel.SharedTransaction(null, InteractiveTxOutput.Shared(0, commitInput.txOut.publicKeyScript, localCommit.spec.toLocal, localCommit.spec.toRemote), listOf(), listOf(), listOf(), listOf(), 0), // We must correctly set the txId here. - TxSignatures(channelId, commitInput.outPoint.hash, listOf()), + TxSignatures(channelId, TxId(commitInput.outPoint.hash), listOf()), ), fr.acinq.lightning.channel.InteractiveTxParams(channelId, localParams.isFunder, commitInput.txOut.amount, commitInput.txOut.amount, remoteParams.fundingPubKey, 0, localParams.dustLimit, localCommit.spec.feerate), 0 diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/bitcoinKSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/bitcoinKSerializers.kt index 3e2511a90..497f68c10 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/bitcoinKSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/bitcoinKSerializers.kt @@ -65,6 +65,18 @@ internal object ByteVector64KSerializer : KSerializer { } } +internal object BlockHashKSerializer : KSerializer { + override fun deserialize(decoder: Decoder): BlockHash { + return BlockHash(ByteVector32KSerializer.deserialize(decoder)) + } + + override val descriptor: SerialDescriptor get() = ByteVector32KSerializer.descriptor + + override fun serialize(encoder: Encoder, value: BlockHash) { + ByteVector32KSerializer.serialize(encoder, value.value) + } +} + internal object PrivateKeyKSerializer : KSerializer { override fun deserialize(decoder: Decoder): PrivateKey { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt index 3955a972a..fd8986f04 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt @@ -4,6 +4,7 @@ EitherSerializer::class, ShaChainSerializer::class, BlockHeaderKSerializer::class, + BlockHashKSerializer::class, FundingSignedSerializer::class, ChannelUpdateSerializer::class, ByteVectorKSerializer::class, @@ -223,7 +224,7 @@ internal data class RemoteCommit( val txid: ByteVector32, val remotePerCommitmentPoint: PublicKey ) { - fun export() = fr.acinq.lightning.channel.RemoteCommit(index, spec.export(), txid, remotePerCommitmentPoint) + fun export() = fr.acinq.lightning.channel.RemoteCommit(index, spec.export(), TxId(txid), remotePerCommitmentPoint) } @Serializable @@ -397,7 +398,7 @@ internal data class Commitments( fr.acinq.lightning.channel.PartiallySignedSharedTransaction( fr.acinq.lightning.channel.SharedTransaction(null, InteractiveTxOutput.Shared(0, commitInput.txOut.publicKeyScript, localCommit.spec.toLocal, localCommit.spec.toRemote), listOf(), listOf(), listOf(), listOf(), 0), // We must correctly set the txId here. - TxSignatures(channelId, commitInput.outPoint.hash, listOf()), + TxSignatures(channelId, TxId(commitInput.outPoint.hash), listOf()), ), fr.acinq.lightning.channel.InteractiveTxParams(channelId, localParams.isFunder, commitInput.txOut.amount, commitInput.txOut.amount, remoteParams.fundingPubKey, 0, localParams.dustLimit, localCommit.spec.feerate), 0 diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/bitcoinKSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/bitcoinKSerializers.kt index 0874d64b4..9259f36c0 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/bitcoinKSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/bitcoinKSerializers.kt @@ -65,6 +65,18 @@ internal object ByteVector64KSerializer : KSerializer { } } +internal object BlockHashKSerializer : KSerializer { + override fun deserialize(decoder: Decoder): BlockHash { + return BlockHash(ByteVector32KSerializer.deserialize(decoder)) + } + + override val descriptor: SerialDescriptor get() = ByteVector32KSerializer.descriptor + + override fun serialize(encoder: Encoder, value: BlockHash) { + ByteVector32KSerializer.serialize(encoder, value.value) + } +} + internal object PrivateKeyKSerializer : KSerializer { override fun deserialize(decoder: Decoder): PrivateKey { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt index 0edf0c81d..98db83189 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt @@ -340,7 +340,7 @@ object Deserialization { remoteCommit = RemoteCommit( index = readNumber(), spec = readCommitmentSpecWithHtlcs(), - txid = readByteVector32(), + txid = readTxId(), remotePerCommitmentPoint = readPublicKey() ) ) @@ -423,7 +423,7 @@ object Deserialization { // We previously didn't store the tx_signatures after the transaction was confirmed. // It is only used to be retransmitted on reconnection if our peer had not received it. // This happens very rarely in practice, so putting dummy values here shouldn't be an issue. - localSigs = TxSignatures(ByteVector32.Zeroes, ByteVector32.Zeroes, listOf()) + localSigs = TxSignatures(ByteVector32.Zeroes, TxId(ByteVector32.Zeroes), listOf()) ) 0x02 -> LocalFundingStatus.ConfirmedFundingTx( signedTx = readTransaction(), @@ -454,7 +454,7 @@ object Deserialization { remoteCommit = RemoteCommit( index = readNumber(), spec = readCommitmentSpecWithoutHtlcs(htlcs.map { it.opposite() }.toSet()), - txid = readByteVector32(), + txid = readTxId(), remotePerCommitmentPoint = readPublicKey() ), nextRemoteCommit = readNullable { @@ -463,7 +463,7 @@ object Deserialization { commit = RemoteCommit( index = readNumber(), spec = readCommitmentSpecWithoutHtlcs(htlcs.map { it.opposite() }.toSet()), - txid = readByteVector32(), + txid = readTxId(), remotePerCommitmentPoint = readPublicKey() ) ) @@ -574,6 +574,8 @@ object Deserialization { private fun Input.readPublicKey() = PublicKey(ByteArray(33).also { read(it, 0, it.size) }) + private fun Input.readTxId(): TxId = TxId(readByteVector32()) + private fun Input.readDelimitedByteArray(): ByteArray { val size = readNumber().toInt() return ByteArray(size).also { read(it, 0, size) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt index f3948de37..3077b451f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt @@ -384,7 +384,7 @@ object Serialization { remoteCommit.run { writeNumber(index) writeCommitmentSpecWithHtlcs(spec) - writeByteVector32(txid) + writeTxId(txid) writePublicKey(remotePerCommitmentPoint) } } @@ -489,14 +489,14 @@ object Serialization { remoteCommit.run { writeNumber(index) writeCommitmentSpecWithoutHtlcs(spec) - writeByteVector32(txid) + writeTxId(txid) writePublicKey(remotePerCommitmentPoint) } writeNullable(nextRemoteCommit) { writeLightningMessage(it.sig) writeNumber(it.commit.index) writeCommitmentSpecWithoutHtlcs(it.commit.spec) - writeByteVector32(it.commit.txid) + writeTxId(it.commit.txid) writePublicKey(it.commit.remotePerCommitmentPoint) } } @@ -639,6 +639,8 @@ object Serialization { private fun Output.writePublicKey(o: PublicKey) = write(o.value.toByteArray()) + private fun Output.writeTxId(o: TxId) = write(o.value.toByteArray()) + private fun Output.writeDelimited(o: ByteArray) { writeNumber(o.size) write(o) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/utils/jsonrpc.kt b/src/commonMain/kotlin/fr/acinq/lightning/utils/jsonrpc.kt index 68544f84a..3c1b49bc1 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/utils/jsonrpc.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/utils/jsonrpc.kt @@ -2,6 +2,7 @@ package fr.acinq.lightning.utils import fr.acinq.bitcoin.ByteVector import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.TxId import fr.acinq.secp256k1.Hex import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable @@ -32,8 +33,8 @@ fun List.asJsonRPCParameters(): List = map { it -> 1 else -> 0 }.asParam() - is ByteVector -> it.toHex().asParam() + is TxId -> it.value.toHex().asParam() is Transaction -> Hex.encode(Transaction.write(it)).asParam() else -> error("Unsupported type ${it::class} as JSON-RPC parameter") } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt index abec2ba24..f68b576de 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt @@ -8,7 +8,9 @@ import fr.acinq.lightning.MilliSatoshi import fr.acinq.lightning.ShortChannelId import fr.acinq.lightning.channel.ChannelType import fr.acinq.lightning.channel.Origin -import fr.acinq.lightning.utils.* +import fr.acinq.lightning.utils.msat +import fr.acinq.lightning.utils.sat +import fr.acinq.lightning.utils.toByteVector sealed class ChannelTlv : Tlv { /** Commitment to where the funds will go in case of a mutual close, which remote node will enforce in case we're compromised. */ @@ -196,13 +198,13 @@ sealed class RevokeAndAckTlv : Tlv { } sealed class ChannelReestablishTlv : Tlv { - data class NextFunding(val txHash: ByteVector32) : ChannelReestablishTlv() { + data class NextFunding(val txId: TxId) : ChannelReestablishTlv() { override val tag: Long get() = NextFunding.tag - override fun write(out: Output) = LightningCodecs.writeBytes(txHash, out) + override fun write(out: Output) = LightningCodecs.writeTxHash(TxHash(txId), out) companion object : TlvValueReader { const val tag: Long = 0 - override fun read(input: Input): NextFunding = NextFunding(LightningCodecs.bytes(input, 32).toByteVector32()) + override fun read(input: Input): NextFunding = NextFunding(TxId(LightningCodecs.txHash(input))) } } @@ -261,7 +263,7 @@ sealed class PleaseOpenChannelTlv : Tlv { override val tag: Long get() = GrandParents.tag override fun write(out: Output) { outpoints.forEach { outpoint -> - LightningCodecs.writeBytes(outpoint.hash.toByteArray(), out) + LightningCodecs.writeTxHash(outpoint.hash, out) LightningCodecs.writeU64(outpoint.index, out) } } @@ -270,7 +272,7 @@ sealed class PleaseOpenChannelTlv : Tlv { const val tag: Long = 561 override fun read(input: Input): GrandParents { val count = input.availableBytes / 40 - val outpoints = (0 until count).map { OutPoint(LightningCodecs.bytes(input, 32).toByteVector32(), LightningCodecs.u64(input)) } + val outpoints = (0 until count).map { OutPoint(LightningCodecs.txHash(input), LightningCodecs.u64(input)) } return GrandParents(outpoints) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt index da9906de0..9e3ea7dd1 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt @@ -5,7 +5,6 @@ import fr.acinq.bitcoin.io.Input import fr.acinq.bitcoin.io.Output import fr.acinq.lightning.utils.sat import fr.acinq.lightning.utils.toByteVector -import fr.acinq.lightning.utils.toByteVector32 import fr.acinq.lightning.utils.toByteVector64 sealed class TxAddInputTlv : Tlv { @@ -13,13 +12,13 @@ sealed class TxAddInputTlv : Tlv { * When doing a splice, the initiator must provide the previous funding txId instead of the whole transaction. * Note that we actually encode this as a tx_hash to be consistent with other lightning messages. */ - data class SharedInputTxId(val txId: ByteVector32) : TxAddInputTlv() { + data class SharedInputTxId(val txId: TxId) : TxAddInputTlv() { override val tag: Long get() = SharedInputTxId.tag - override fun write(out: Output) = LightningCodecs.writeBytes(txId.reversed(), out) + override fun write(out: Output) = LightningCodecs.writeTxHash(TxHash(txId), out) companion object : TlvValueReader { const val tag: Long = 1105 - override fun read(input: Input): SharedInputTxId = SharedInputTxId(LightningCodecs.bytes(input, 32).toByteVector32().reversed()) + override fun read(input: Input): SharedInputTxId = SharedInputTxId(TxId(LightningCodecs.txHash(input))) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningCodecs.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningCodecs.kt index e29600507..4cef0538c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningCodecs.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningCodecs.kt @@ -2,6 +2,8 @@ package fr.acinq.lightning.wire import fr.acinq.bitcoin.ByteVector import fr.acinq.bitcoin.ByteVector32 +import fr.acinq.bitcoin.TxHash +import fr.acinq.bitcoin.TxId import fr.acinq.bitcoin.crypto.Pack import fr.acinq.bitcoin.io.ByteArrayOutput import fr.acinq.bitcoin.io.Input @@ -205,6 +207,18 @@ object LightningCodecs { @JvmStatic fun writeBytes(input: ByteVector32, out: Output): Unit = writeBytes(input.toByteArray(), out) + @JvmStatic + fun txId(input: Input): TxId = TxId(bytes(input, 32)) + + @JvmStatic + fun writeTxId(input: TxId, out: Output): Unit = writeBytes(input.value.toByteArray(), out) + + @JvmStatic + fun txHash(input: Input): TxHash = TxHash(bytes(input, 32)) + + @JvmStatic + fun writeTxHash(input: TxHash, out: Output): Unit = writeBytes(input.value.toByteArray(), out) + @JvmStatic fun script(input: Input): ByteArray { val length = bigSize(input) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt index 58148e87e..a526e4361 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt @@ -137,7 +137,7 @@ interface HasSerialId : LightningMessage { } interface HasChainHash : LightningMessage { - val chainHash: ByteVector32 + val chainHash: BlockHash } interface ForbiddenMessageDuringSplice : LightningMessage @@ -327,7 +327,7 @@ data class TxAddInput( ) override val type: Long get() = TxAddInput.type - val sharedInput: OutPoint? = tlvs.get()?.let { OutPoint(it.txId.reversed(), previousTxOutput) } + val sharedInput: OutPoint? = tlvs.get()?.let { OutPoint(it.txId, previousTxOutput) } val swapInParams = tlvs.get() override fun write(out: Output) { @@ -459,13 +459,13 @@ data class TxComplete( data class TxSignatures( override val channelId: ByteVector32, - val txHash: ByteVector32, + val txId: TxId, val witnesses: List, val tlvs: TlvStream = TlvStream.empty() ) : InteractiveTxMessage(), HasChannelId, HasEncryptedChannelData { constructor(channelId: ByteVector32, tx: Transaction, witnesses: List, previousFundingSig: ByteVector64?, swapInUserSigs: List, swapInServerSigs: List) : this( channelId, - tx.hash, + tx.txid, witnesses, TlvStream( listOfNotNull( @@ -478,7 +478,6 @@ data class TxSignatures( override val type: Long get() = TxSignatures.type - val txId: ByteVector32 = txHash.reversed() val previousFundingTxSig: ByteVector64? = tlvs.get()?.sig val swapInUserSigs: List = tlvs.get()?.sigs ?: listOf() val swapInServerSigs: List = tlvs.get()?.sigs ?: listOf() @@ -488,7 +487,8 @@ data class TxSignatures( override fun write(out: Output) { LightningCodecs.writeBytes(channelId.toByteArray(), out) - LightningCodecs.writeBytes(txHash.toByteArray(), out) + // Note that we encode the tx_hash instead of the tx_id to be consistent with other lightning messages. + LightningCodecs.writeTxHash(TxHash(txId), out) LightningCodecs.writeU16(witnesses.size, out) witnesses.forEach { witness -> val witnessData = ScriptWitness.write(witness) @@ -511,13 +511,13 @@ data class TxSignatures( override fun read(input: Input): TxSignatures { val channelId = LightningCodecs.bytes(input, 32).byteVector32() - val txHash = LightningCodecs.bytes(input, 32).byteVector32() + val txHash = LightningCodecs.txHash(input) val witnessCount = LightningCodecs.u16(input) val witnesses = (1..witnessCount).map { val witnessSize = LightningCodecs.u16(input) ScriptWitness.read(LightningCodecs.bytes(input, witnessSize)) } - return TxSignatures(channelId, txHash, witnesses, TlvStreamSerializer(false, readers).read(input)) + return TxSignatures(channelId, TxId(txHash), witnesses, TlvStreamSerializer(false, readers).read(input)) } } } @@ -612,7 +612,7 @@ data class TxAbort( } data class OpenDualFundedChannel( - override val chainHash: ByteVector32, + override val chainHash: BlockHash, override val temporaryChannelId: ByteVector32, val fundingFeerate: FeeratePerKw, val commitmentFeerate: FeeratePerKw, @@ -640,7 +640,7 @@ data class OpenDualFundedChannel( override val type: Long get() = OpenDualFundedChannel.type override fun write(out: Output) { - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeBytes(temporaryChannelId, out) LightningCodecs.writeU32(fundingFeerate.toLong().toInt(), out) LightningCodecs.writeU32(commitmentFeerate.toLong().toInt(), out) @@ -675,7 +675,7 @@ data class OpenDualFundedChannel( ) override fun read(input: Input): OpenDualFundedChannel = OpenDualFundedChannel( - ByteVector32(LightningCodecs.bytes(input, 32)), + BlockHash(LightningCodecs.bytes(input, 32)), ByteVector32(LightningCodecs.bytes(input, 32)), FeeratePerKw(LightningCodecs.u32(input).toLong().sat), FeeratePerKw(LightningCodecs.u32(input).toLong().sat), @@ -949,15 +949,14 @@ data class SpliceAck( data class SpliceLocked( override val channelId: ByteVector32, - val fundingTxHash: ByteVector32, + val fundingTxId: TxId, val tlvStream: TlvStream = TlvStream.empty() ) : ChannelMessage, HasChannelId { override val type: Long get() = SpliceLocked.type - val fundingTxId = fundingTxHash.reversed() override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) - LightningCodecs.writeBytes(fundingTxHash, out) + LightningCodecs.writeTxHash(TxHash(fundingTxId), out) TlvStreamSerializer(false, readers).write(tlvStream, out) } @@ -968,7 +967,7 @@ data class SpliceLocked( override fun read(input: Input): SpliceLocked = SpliceLocked( channelId = ByteVector32(LightningCodecs.bytes(input, 32)), - fundingTxHash = ByteVector32(LightningCodecs.bytes(input, 32)), + fundingTxId = TxId(LightningCodecs.txHash(input)), tlvStream = TlvStreamSerializer(false, readers).read(input) ) } @@ -1201,7 +1200,7 @@ data class ChannelReestablish( ) : HasChannelId, HasEncryptedChannelData { override val type: Long get() = ChannelReestablish.type - val nextFundingTxId: ByteVector32? = tlvStream.get()?.txHash?.reversed() + val nextFundingTxId: TxId? = tlvStream.get()?.txId override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty override fun withNonEmptyChannelData(ecd: EncryptedChannelData): ChannelReestablish = copy(tlvStream = tlvStream.addOrUpdate(ChannelReestablishTlv.ChannelData(ecd))) @@ -1271,7 +1270,7 @@ data class ChannelAnnouncement( val bitcoinSignature1: ByteVector64, val bitcoinSignature2: ByteVector64, val features: Features, - override val chainHash: ByteVector32, + override val chainHash: BlockHash, val shortChannelId: ShortChannelId, val nodeId1: PublicKey, val nodeId2: PublicKey, @@ -1289,7 +1288,7 @@ data class ChannelAnnouncement( val featureBytes = features.toByteArray() LightningCodecs.writeU16(featureBytes.size, out) LightningCodecs.writeBytes(featureBytes, out) - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeU64(shortChannelId.toLong(), out) LightningCodecs.writeBytes(nodeId1.value, out) LightningCodecs.writeBytes(nodeId2.value, out) @@ -1307,7 +1306,7 @@ data class ChannelAnnouncement( val bitcoinSignature1 = LightningCodecs.bytes(input, 64).toByteVector64() val bitcoinSignature2 = LightningCodecs.bytes(input, 64).toByteVector64() val featureBytes = LightningCodecs.bytes(input, LightningCodecs.u16(input)) - val chainHash = LightningCodecs.bytes(input, 32).toByteVector32() + val chainHash = BlockHash(LightningCodecs.bytes(input, 32)) val shortChannelId = ShortChannelId(LightningCodecs.u64(input)) val nodeId1 = PublicKey(LightningCodecs.bytes(input, 33)) val nodeId2 = PublicKey(LightningCodecs.bytes(input, 33)) @@ -1334,7 +1333,7 @@ data class ChannelAnnouncement( data class ChannelUpdate( val signature: ByteVector64, - override val chainHash: ByteVector32, + override val chainHash: BlockHash, val shortChannelId: ShortChannelId, override val timestampSeconds: Long, val messageFlags: Byte, @@ -1362,7 +1361,7 @@ data class ChannelUpdate( override fun write(out: Output) { LightningCodecs.writeBytes(signature, out) - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeU64(shortChannelId.toLong(), out) LightningCodecs.writeU32(timestampSeconds.toInt(), out) LightningCodecs.writeByte(messageFlags.toInt(), out) @@ -1382,7 +1381,7 @@ data class ChannelUpdate( override fun read(input: Input): ChannelUpdate { val signature = ByteVector64(LightningCodecs.bytes(input, 64)) - val chainHash = ByteVector32(LightningCodecs.bytes(input, 32)) + val chainHash = BlockHash(LightningCodecs.bytes(input, 32)) val shortChannelId = ShortChannelId(LightningCodecs.u64(input)) val timestampSeconds = LightningCodecs.u32(input).toLong() val messageFlags = LightningCodecs.byte(input).toByte() @@ -1520,7 +1519,7 @@ data class OnionMessage( * @param finalPacket onion packet that we would have received if there had been a channel to forward the payment to. */ data class PayToOpenRequest( - override val chainHash: ByteVector32, + override val chainHash: BlockHash, val fundingSatoshis: Satoshi, val amountMsat: MilliSatoshi, val payToOpenMinAmountMsat: MilliSatoshi, @@ -1532,7 +1531,7 @@ data class PayToOpenRequest( override val type: Long get() = PayToOpenRequest.type override fun write(out: Output) { - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeU64(fundingSatoshis.toLong(), out) LightningCodecs.writeU64(amountMsat.toLong(), out) LightningCodecs.writeU64(payToOpenMinAmountMsat.toLong(), out) @@ -1548,7 +1547,7 @@ data class PayToOpenRequest( override fun read(input: Input): PayToOpenRequest { return PayToOpenRequest( - chainHash = ByteVector32(LightningCodecs.bytes(input, 32)), + chainHash = BlockHash(LightningCodecs.bytes(input, 32)), fundingSatoshis = Satoshi(LightningCodecs.u64(input)), amountMsat = MilliSatoshi(LightningCodecs.u64(input)), payToOpenMinAmountMsat = MilliSatoshi(LightningCodecs.u64(input)), @@ -1561,7 +1560,7 @@ data class PayToOpenRequest( } } -data class PayToOpenResponse(override val chainHash: ByteVector32, val paymentHash: ByteVector32, val result: Result) : LightningMessage, HasChainHash { +data class PayToOpenResponse(override val chainHash: BlockHash, val paymentHash: ByteVector32, val result: Result) : LightningMessage, HasChainHash { override val type: Long get() = PayToOpenResponse.type sealed class Result { @@ -1573,7 +1572,7 @@ data class PayToOpenResponse(override val chainHash: ByteVector32, val paymentHa } override fun write(out: Output) { - LightningCodecs.writeBytes(chainHash, out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeBytes(paymentHash, out) when (result) { is Result.Success -> LightningCodecs.writeBytes(result.paymentPreimage, out) @@ -1591,7 +1590,7 @@ data class PayToOpenResponse(override val chainHash: ByteVector32, val paymentHa const val type: Long = 35003 override fun read(input: Input): PayToOpenResponse { - val chainHash = LightningCodecs.bytes(input, 32).toByteVector32() + val chainHash = BlockHash(LightningCodecs.bytes(input, 32)) val paymentHash = LightningCodecs.bytes(input, 32).toByteVector32() return when (val preimage = LightningCodecs.bytes(input, 32).toByteVector32()) { ByteVector32.Zeroes -> { @@ -1656,7 +1655,7 @@ data class PhoenixAndroidLegacyInfo( * in the [AcceptDualFundedChannel] message. */ data class PleaseOpenChannel( - override val chainHash: ByteVector32, + override val chainHash: BlockHash, val requestId: ByteVector32, val localFundingAmount: Satoshi, val localInputsCount: Int, @@ -1668,7 +1667,7 @@ data class PleaseOpenChannel( val grandParents: List = tlvs.get()?.outpoints ?: listOf() override fun write(out: Output) { - LightningCodecs.writeBytes(chainHash.toByteArray(), out) + LightningCodecs.writeBytes(chainHash.value, out) LightningCodecs.writeBytes(requestId.toByteArray(), out) LightningCodecs.writeU64(localFundingAmount.toLong(), out) LightningCodecs.writeU16(localInputsCount, out) @@ -1685,7 +1684,7 @@ data class PleaseOpenChannel( ) override fun read(input: Input): PleaseOpenChannel = PleaseOpenChannel( - LightningCodecs.bytes(input, 32).toByteVector32(), + BlockHash(LightningCodecs.bytes(input, 32)), LightningCodecs.bytes(input, 32).toByteVector32(), LightningCodecs.u64(input).sat, LightningCodecs.u16(input), diff --git a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientTest.kt b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientTest.kt index b1ed92363..fb9c432b5 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientTest.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumClientTest.kt @@ -78,7 +78,7 @@ class ElectrumClientTest : LightningTestSuite() { @Test fun `get transaction -- not found`() = runTest { client -> - val tx = client.getTx(ByteVector32.Zeroes) + val tx = client.getTx(TxId(ByteVector32.Zeroes)) assertNull(tx) client.stop() } @@ -88,7 +88,7 @@ class ElectrumClientTest : LightningTestSuite() { val header = client.getHeader(100000) assertNotNull(header) assertEquals( - Hex.decode("000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506").byteVector32(), + BlockId(Hex.decode("000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506")), header.blockId ) client.stop() @@ -121,7 +121,7 @@ class ElectrumClientTest : LightningTestSuite() { val merkle = client.getMerkle(referenceTx.txid, 500000) assertNotNull(merkle) assertEquals(referenceTx.txid, merkle.txid) - assertEquals(500000, merkle.block_height) + assertEquals(500000, merkle.blockHeight) assertEquals(2690, merkle.pos) assertEquals( Hex.decode("1f6231ed3de07345b607ec2a39b2d01bec2fe10dfb7f516ba4958a42691c9531").byteVector32(), @@ -177,16 +177,16 @@ class ElectrumClientTest : LightningTestSuite() { @Test fun `client multiplexing`() = runTest { client -> val txids = listOf( - ByteVector32("c1e943938e0bf2e9e6feefe22af0466514a58e9f7ed0f7ada6fd8e6dbeca0742"), - ByteVector32("2cf392ecf573a638f01f72c276c3b097d05eb58f39e165eacc91b8a8df09fbd8"), - ByteVector32("149a098d6261b7f9359a572d797c4a41b62378836a14093912618b15644ba402"), - ByteVector32("2dd9cb7bcebb74b02efc85570a462f22a54a613235bee11d0a2c791342a26007"), - ByteVector32("71b3dbaca67e9f9189dad3617138c19725ab541ef0b49c05a94913e9f28e3f4e"), - ByteVector32("21d2eb195736af2a40d42107e6abd59c97eb6cffd4a5a7a7709e86590ae61987"), - ByteVector32("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"), - ByteVector32("563ea83f9641d37a36f9294d172fdb4fb86c19b0e9cac45e0b27610331138775"), - ByteVector32("971af80218684017722429be08548d1f30a2f1f220abc064380cbca5cabf7623"), - ByteVector32("b1ec9c44009147f3cee26caba45abec2610c74df9751fad14074119b5314da21") + TxId("c1e943938e0bf2e9e6feefe22af0466514a58e9f7ed0f7ada6fd8e6dbeca0742"), + TxId("2cf392ecf573a638f01f72c276c3b097d05eb58f39e165eacc91b8a8df09fbd8"), + TxId("149a098d6261b7f9359a572d797c4a41b62378836a14093912618b15644ba402"), + TxId("2dd9cb7bcebb74b02efc85570a462f22a54a613235bee11d0a2c791342a26007"), + TxId("71b3dbaca67e9f9189dad3617138c19725ab541ef0b49c05a94913e9f28e3f4e"), + TxId("21d2eb195736af2a40d42107e6abd59c97eb6cffd4a5a7a7709e86590ae61987"), + TxId("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"), + TxId("563ea83f9641d37a36f9294d172fdb4fb86c19b0e9cac45e0b27610331138775"), + TxId("971af80218684017722429be08548d1f30a2f1f220abc064380cbca5cabf7623"), + TxId("b1ec9c44009147f3cee26caba45abec2610c74df9751fad14074119b5314da21") ) // request txids in parallel @@ -208,8 +208,8 @@ class ElectrumClientTest : LightningTestSuite() { is ElectrumConnectionStatus.Connected -> status.height else -> null }!! - assertEquals(currentBlockHeight - confirmedAt, client.getConfirmations(ByteVector32("f1c290880b6fc9355e4f1b1b7d13b9a15babbe096adaf13d01f3a56def793fd5"))) - assertNull(client.getConfirmations(ByteVector32("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))) + assertEquals(currentBlockHeight - confirmedAt, client.getConfirmations(TxId("f1c290880b6fc9355e4f1b1b7d13b9a15babbe096adaf13d01f3a56def793fd5"))) + assertNull(client.getConfirmations(TxId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))) client.stop() } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletTest.kt b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletTest.kt index 9dc545694..f95b46687 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletTest.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletTest.kt @@ -2,8 +2,8 @@ package fr.acinq.lightning.blockchain.electrum import fr.acinq.bitcoin.Bitcoin import fr.acinq.bitcoin.Block -import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.SwapInParams import fr.acinq.lightning.tests.utils.LightningTestSuite import fr.acinq.lightning.tests.utils.runSuspendTest @@ -132,17 +132,17 @@ class ElectrumMiniWalletTest : LightningTestSuite() { assertEquals( expected = setOf( - Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", ByteVector32("c1e943938e0bf2e9e6feefe22af0466514a58e9f7ed0f7ada6fd8e6dbeca0742") to 1, 39_000_000.sat), - Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", ByteVector32("2cf392ecf573a638f01f72c276c3b097d05eb58f39e165eacc91b8a8df09fbd8") to 0, 12_000_000.sat), - Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", ByteVector32("149a098d6261b7f9359a572d797c4a41b62378836a14093912618b15644ba402") to 1, 11_000_000.sat), - Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", ByteVector32("2dd9cb7bcebb74b02efc85570a462f22a54a613235bee11d0a2c791342a26007") to 1, 10_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("71b3dbaca67e9f9189dad3617138c19725ab541ef0b49c05a94913e9f28e3f4e") to 0, 5_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("21d2eb195736af2a40d42107e6abd59c97eb6cffd4a5a7a7709e86590ae61987") to 0, 5_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20") to 1, 5_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("563ea83f9641d37a36f9294d172fdb4fb86c19b0e9cac45e0b27610331138775") to 0, 5_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("971af80218684017722429be08548d1f30a2f1f220abc064380cbca5cabf7623") to 1, 5_000_000.sat), - Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", ByteVector32("b1ec9c44009147f3cee26caba45abec2610c74df9751fad14074119b5314da21") to 0, 5_000_000.sat), - Triple("1NHFyu1uJ1UoDjtPjqZ4Et3wNCyMGCJ1qV", ByteVector32("602839d82ac6c9aafd1a20fff5b23e11a99271e7cc238d2e48b352219b2b87ab") to 1, 2_000_000.sat), + Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", TxId("c1e943938e0bf2e9e6feefe22af0466514a58e9f7ed0f7ada6fd8e6dbeca0742") to 1, 39_000_000.sat), + Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", TxId("2cf392ecf573a638f01f72c276c3b097d05eb58f39e165eacc91b8a8df09fbd8") to 0, 12_000_000.sat), + Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", TxId("149a098d6261b7f9359a572d797c4a41b62378836a14093912618b15644ba402") to 1, 11_000_000.sat), + Triple("16MmJT8VqW465GEyckWae547jKVfMB14P8", TxId("2dd9cb7bcebb74b02efc85570a462f22a54a613235bee11d0a2c791342a26007") to 1, 10_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("71b3dbaca67e9f9189dad3617138c19725ab541ef0b49c05a94913e9f28e3f4e") to 0, 5_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("21d2eb195736af2a40d42107e6abd59c97eb6cffd4a5a7a7709e86590ae61987") to 0, 5_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20") to 1, 5_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("563ea83f9641d37a36f9294d172fdb4fb86c19b0e9cac45e0b27610331138775") to 0, 5_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("971af80218684017722429be08548d1f30a2f1f220abc064380cbca5cabf7623") to 1, 5_000_000.sat), + Triple("14xb2HATmkBzrHf4CR2hZczEtjYpTh92d2", TxId("b1ec9c44009147f3cee26caba45abec2610c74df9751fad14074119b5314da21") to 0, 5_000_000.sat), + Triple("1NHFyu1uJ1UoDjtPjqZ4Et3wNCyMGCJ1qV", TxId("602839d82ac6c9aafd1a20fff5b23e11a99271e7cc238d2e48b352219b2b87ab") to 1, 2_000_000.sat), ), actual = walletState.utxos.map { val txOut = it.previousTx.txOut[it.outputIndex] diff --git a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumRequestTest.kt b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumRequestTest.kt index 2e31f5d8d..83d15579a 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumRequestTest.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumRequestTest.kt @@ -1,5 +1,6 @@ package fr.acinq.lightning.blockchain.electrum +import fr.acinq.bitcoin.BlockHash import fr.acinq.bitcoin.BlockHeader import fr.acinq.bitcoin.ByteVector32 import fr.acinq.lightning.tests.utils.LightningTestSuite @@ -53,7 +54,7 @@ class ElectrumRequestTest : LightningTestSuite() { assertEquals( Either.Left(HeaderSubscriptionResponse(blockHeight = 520481, BlockHeader( version = 536870912, - hashPreviousBlock = ByteVector32.fromValidHex("890208a0ae3a3892aa047c5468725846577cfcd9b512b5000000000000000000"), + hashPreviousBlock = BlockHash("890208a0ae3a3892aa047c5468725846577cfcd9b512b5000000000000000000"), hashMerkleRoot = ByteVector32.fromValidHex("5dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8e"), time = 1520495819, bits = 402858285, diff --git a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt index a6b7d95f3..498bc043c 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt @@ -284,7 +284,7 @@ class ElectrumWatcherIntegrationTest : LightningTestSuite() { val mempool = bitcoincli.getRawMempool() if (mempool.isNotEmpty()) { assertEquals(1, mempool.size) - assertEquals(tx.txid.toHex(), mempool.first()) + assertEquals(tx.txid.value.toHex(), mempool.first()) } delay(1.seconds) } while (mempool.isEmpty()) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManagerTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManagerTestsCommon.kt index a92a4f392..ef009be9e 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManagerTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManagerTestsCommon.kt @@ -31,8 +31,8 @@ class SwapInManagerTestsCommon : LightningTestSuite() { val mgr = SwapInManager(listOf(), logger) val wallet = run { val parentTxs = listOf( - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 2), 0)), listOf(TxOut(50_000.sat, dummyScript), TxOut(75_000.sat, dummyScript)), 0), - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)), listOf(TxOut(50_000.sat, dummyScript), TxOut(75_000.sat, dummyScript)), 0), + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) ) val unspent = listOf( UnspentItem(parentTxs[0].txid, 0, 50_000, 100), // deeply confirmed @@ -53,8 +53,8 @@ class SwapInManagerTestsCommon : LightningTestSuite() { val mgr = SwapInManager(listOf(), logger) val wallet = run { val parentTxs = listOf( - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) ) val unspent = listOf( UnspentItem(parentTxs[0].txid, 0, 50_000, 100), // recently confirmed @@ -71,8 +71,8 @@ class SwapInManagerTestsCommon : LightningTestSuite() { val mgr = SwapInManager(listOf(), logger) val wallet = run { val parentTxs = listOf( - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) ) val unspent = listOf( UnspentItem(parentTxs[0].txid, 0, 50_000, 100), // exceeds refund delay @@ -88,9 +88,9 @@ class SwapInManagerTestsCommon : LightningTestSuite() { fun `swap funds -- allow unconfirmed in migration`() { val mgr = SwapInManager(listOf(), logger) val parentTxs = listOf( - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 1), 0)), listOf(TxOut(75_000.sat, dummyScript)), 0), - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), - Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 1), 0)), listOf(TxOut(75_000.sat, dummyScript)), 0), + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)), listOf(TxOut(50_000.sat, dummyScript)), 0), + Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(25_000.sat, dummyScript)), 0) ) val wallet = run { val unspent = listOf( @@ -111,7 +111,7 @@ class SwapInManagerTestsCommon : LightningTestSuite() { fun `swap funds -- previously used inputs`() { val mgr = SwapInManager(listOf(), logger) val wallet = run { - val parentTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 1), 0)), listOf(TxOut(75_000.sat, dummyScript)), 0) + val parentTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 1), 0)), listOf(TxOut(75_000.sat, dummyScript)), 0) val unspent = UnspentItem(parentTx.txid, 0, 75_000, 100) WalletState(mapOf(dummyAddress to listOf(unspent)), mapOf(parentTx.txid to parentTx)) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/ChannelDataTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/ChannelDataTestsCommon.kt index 81daffa42..230c60713 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/ChannelDataTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/ChannelDataTestsCommon.kt @@ -326,7 +326,7 @@ class ChannelDataTestsCommon : LightningTestSuite(), LoggingContext { private fun createClosingTransactions(): Triple { val commitTx = Transaction( 2, - listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), + listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf( TxOut(50_000.sat, ByteVector.empty), // main output Alice TxOut(40_000.sat, ByteVector.empty), // main output Bob diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/CommitmentsTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/CommitmentsTestsCommon.kt index df0afa7c6..a41ae267c 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/CommitmentsTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/CommitmentsTestsCommon.kt @@ -493,7 +493,7 @@ class CommitmentsTestsCommon : LightningTestSuite(), LoggingContext { ) val fundingAmount = (toLocal + toRemote).truncateToSatoshi() val dummyFundingScript = Scripts.multiSig2of2(randomKey().publicKey(), randomKey().publicKey()) - val dummyFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 1), 0)), listOf(TxOut(fundingAmount, Script.pay2wsh(dummyFundingScript))), 0) + val dummyFundingTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 1), 0)), listOf(TxOut(fundingAmount, Script.pay2wsh(dummyFundingScript))), 0) val commitmentInput = Transactions.InputInfo(OutPoint(dummyFundingTx, 0), dummyFundingTx.txOut[0], dummyFundingScript) val localCommitTx = Transactions.TransactionWithInputInfo.CommitTx(commitmentInput, Transaction(2, listOf(), listOf(), 0)) return Commitments( @@ -515,10 +515,10 @@ class CommitmentsTestsCommon : LightningTestSuite(), LoggingContext { Commitment( fundingTxIndex = 0, remoteFundingPubkey = randomKey().publicKey(), - LocalFundingStatus.ConfirmedFundingTx(dummyFundingTx, 500.sat, TxSignatures(randomBytes32(), randomBytes32(), listOf())), + LocalFundingStatus.ConfirmedFundingTx(dummyFundingTx, 500.sat, TxSignatures(randomBytes32(), TxId(randomBytes32()), listOf())), RemoteFundingStatus.Locked, LocalCommit(0, CommitmentSpec(setOf(), feeRatePerKw, toLocal, toRemote), PublishableTxs(localCommitTx, listOf())), - RemoteCommit(0, CommitmentSpec(setOf(), feeRatePerKw, toRemote, toLocal), randomBytes32(), randomKey().publicKey()), + RemoteCommit(0, CommitmentSpec(setOf(), feeRatePerKw, toRemote, toLocal), TxId(randomBytes32()), randomKey().publicKey()), nextRemoteCommit = null, ) ), @@ -538,7 +538,7 @@ class CommitmentsTestsCommon : LightningTestSuite(), LoggingContext { ) val fundingAmount = (toLocal + toRemote).truncateToSatoshi() val dummyFundingScript = Scripts.multiSig2of2(randomKey().publicKey(), randomKey().publicKey()) - val dummyFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 1), 0)), listOf(TxOut(fundingAmount, Script.pay2wsh(dummyFundingScript))), 0) + val dummyFundingTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 1), 0)), listOf(TxOut(fundingAmount, Script.pay2wsh(dummyFundingScript))), 0) val commitmentInput = Transactions.InputInfo(OutPoint(dummyFundingTx, 0), dummyFundingTx.txOut[0], dummyFundingScript) val localCommitTx = Transactions.TransactionWithInputInfo.CommitTx(commitmentInput, Transaction(2, listOf(), listOf(), 0)) return Commitments( @@ -560,10 +560,10 @@ class CommitmentsTestsCommon : LightningTestSuite(), LoggingContext { Commitment( fundingTxIndex = 0, remoteFundingPubkey = randomKey().publicKey(), - LocalFundingStatus.ConfirmedFundingTx(dummyFundingTx, 500.sat, TxSignatures(randomBytes32(), randomBytes32(), listOf())), + LocalFundingStatus.ConfirmedFundingTx(dummyFundingTx, 500.sat, TxSignatures(randomBytes32(), TxId(randomBytes32()), listOf())), RemoteFundingStatus.Locked, LocalCommit(0, CommitmentSpec(setOf(), FeeratePerKw(0.sat), toLocal, toRemote), PublishableTxs(localCommitTx, listOf())), - RemoteCommit(0, CommitmentSpec(setOf(), FeeratePerKw(0.sat), toRemote, toLocal), randomBytes32(), randomKey().publicKey()), + RemoteCommit(0, CommitmentSpec(setOf(), FeeratePerKw(0.sat), toRemote, toLocal), TxId(randomBytes32()), randomKey().publicKey()), nextRemoteCommit = null ) ), diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/HelpersTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/HelpersTestsCommon.kt index 40987f2b4..b62c61501 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/HelpersTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/HelpersTestsCommon.kt @@ -21,18 +21,16 @@ class HelpersTestsCommon : LightningTestSuite() { fun `compute address from pubkey script`() { val pub = PrivateKey(Hex.decode("0101010101010101010101010101010101010101010101010101010101010101")).publicKey() - fun address(script: List, chainHash: ByteVector32) = - Helpers.Closing.btcAddressFromScriptPubKey(ByteVector(Script.write(script)), chainHash) - + fun address(script: List, chainHash: BlockHash) = Bitcoin.addressFromPublicKeyScript(chainHash, Script.write(script)).result listOf(Block.LivenetGenesisBlock.hash, Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash).forEach { assertEquals(address(Script.pay2pkh(pub), it), computeP2PkhAddress(pub, it)) assertEquals(address(Script.pay2wpkh(pub), it), computeP2WpkhAddress(pub, it)) assertEquals(address(Script.pay2sh(Script.pay2wpkh(pub)), it), computeP2ShOfP2WpkhAddress(pub, it)) // all these chain hashes are invalid - assertEquals(address(Script.pay2pkh(pub), it.reversed()), null) - assertEquals(address(Script.pay2wpkh(pub), it.reversed()), null) - assertEquals(address(Script.pay2sh(Script.pay2wpkh(pub)), it.reversed()), null) + assertEquals(address(Script.pay2pkh(pub), BlockHash(it.value.reversed())), null) + assertEquals(address(Script.pay2wpkh(pub), BlockHash(it.value.reversed())), null) + assertEquals(address(Script.pay2sh(Script.pay2wpkh(pub)), BlockHash(it.value.reversed())), null) } listOf( @@ -46,10 +44,7 @@ class HelpersTestsCommon : LightningTestSuite() { Triple("a91481b9ac6a59b53927da7277b5ad5460d781b365d987", Block.LivenetGenesisBlock.hash, "3DWwX7NYjnav66qygrm4mBCpiByjammaWy"), ).forEach { assertEquals( - Helpers.Closing.btcAddressFromScriptPubKey( - scriptPubKey = ByteVector(Hex.decode(it.first)), - chainHash = it.second - ), + Bitcoin.addressFromPublicKeyScript(it.second, Hex.decode(it.first)).result, it.third ) } @@ -71,7 +66,7 @@ class HelpersTestsCommon : LightningTestSuite() { ) fun toClosingTx(txOut: List): Transactions.TransactionWithInputInfo.ClosingTx { - val input = Transactions.InputInfo(OutPoint(ByteVector32.Zeroes, 0), TxOut(1000.sat, listOf()), listOf()) + val input = Transactions.InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 0), TxOut(1000.sat, listOf()), listOf()) return Transactions.TransactionWithInputInfo.ClosingTx(input, Transaction(2, listOf(), txOut, 0), null) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/InteractiveTxTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/InteractiveTxTestsCommon.kt index bd04b820e..82e9c8663 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/InteractiveTxTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/InteractiveTxTestsCommon.kt @@ -79,7 +79,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() { assertEquals(signedTxB.localSigs.swapInServerSigs.size, 3) // Alice detects invalid signatures from Bob. - val sigsInvalidTxId = signedTxB.localSigs.copy(txHash = randomBytes32()) + val sigsInvalidTxId = signedTxB.localSigs.copy(txId = TxId(randomBytes32())) assertNull(sharedTxA.sharedTx.sign(f.keyManagerA, f.fundingParamsA, f.localParamsA, f.localParamsB.nodeId).addRemoteSigs(f.channelKeysA, f.fundingParamsA, sigsInvalidTxId)) val sigsMissingUserSigs = signedTxB.localSigs.copy(tlvs = TlvStream(TxSignaturesTlv.SwapInUserSigs(listOf()), TxSignaturesTlv.SwapInServerSigs(signedTxB.localSigs.swapInServerSigs))) assertNull(sharedTxA.sharedTx.sign(f.keyManagerA, f.fundingParamsA, f.localParamsA, f.localParamsB.nodeId).addRemoteSigs(f.channelKeysA, f.fundingParamsA, sigsMissingUserSigs)) @@ -641,7 +641,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() { assertIs(result) } run { - val txIn = (1..1000).map { TxIn(OutPoint(randomBytes32(), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(pubKey, Transactions.PlaceHolderSig)) } + val txIn = (1..1000).map { TxIn(OutPoint(TxId(randomBytes32()), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(pubKey, Transactions.PlaceHolderSig)) } val txOut = (1..1000).map { i -> TxOut(1000.sat * i, Script.pay2wpkh(pubKey)) } val previousTx = Transaction(2, txIn, txOut, 0) val result = FundingContributions.create(channelKeys, swapInKeys, fundingParams, listOf(WalletState.Utxo(previousTx, 53, 0))).left @@ -987,13 +987,13 @@ class InteractiveTxTestsCommon : LightningTestSuite() { val validScript = Script.write(Script.pay2wpkh(randomKey().publicKey())).byteVector() val firstAttempt = FullySignedSharedTransaction( SharedTransaction(null, sharedOutput, listOf(), listOf(InteractiveTxInput.RemoteOnly(2, OutPoint(previousTx1, 0), TxOut(125_000.sat, validScript), 0u)), listOf(), listOf(), 0), - TxSignatures(f.channelId, randomBytes32(), listOf()), - TxSignatures(f.channelId, randomBytes32(), listOf(Script.witnessPay2wpkh(randomKey().publicKey(), ByteVector64.Zeroes))), + TxSignatures(f.channelId, TxId(randomBytes32()), listOf()), + TxSignatures(f.channelId, TxId(randomBytes32()), listOf(Script.witnessPay2wpkh(randomKey().publicKey(), ByteVector64.Zeroes))), sharedSigs = null ) val secondAttempt = PartiallySignedSharedTransaction( SharedTransaction(null, sharedOutput, listOf(), firstAttempt.tx.remoteInputs + listOf(InteractiveTxInput.RemoteOnly(4, OutPoint(previousTx2, 1), TxOut(150_000.sat, validScript), 0u)), listOf(), listOf(), 0), - TxSignatures(f.channelId, randomBytes32(), listOf()), + TxSignatures(f.channelId, TxId(randomBytes32()), listOf()), ) val bob0 = InteractiveTxSession(f.channelKeysB, f.keyManagerB.swapInOnChainWallet, f.fundingParamsB, 0.msat, 0.msat, f.fundingContributionsB, listOf(firstAttempt, secondAttempt)) // Alice --- tx_add_input --> Bob @@ -1135,7 +1135,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() { val redeemScript = Scripts.multiSig2of2(fundingPubkeyA, fundingPubkeyB) val fundingScript = Script.write(Script.pay2wsh(redeemScript)).byteVector() val previousFundingAmount = (balanceA + balanceB).truncateToSatoshi() - val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0) + val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0) val inputInfo = Transactions.InputInfo(OutPoint(previousFundingTx, 0), previousFundingTx.txOut[0], redeemScript) val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex)) val nextFundingPubkeyB = channelKeysB.fundingPubKey(fundingTxIndex + 1) @@ -1169,7 +1169,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() { val redeemScript = Scripts.multiSig2of2(fundingPubkeyA, fundingPubkeyB) val fundingScript = Script.write(Script.pay2wsh(redeemScript)).byteVector() val previousFundingAmount = (balanceA + balanceB).truncateToSatoshi() - val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0) + val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0) val inputInfo = Transactions.InputInfo(OutPoint(previousFundingTx, 0), previousFundingTx.txOut[0], redeemScript) val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex)) val sharedInputB = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysA.fundingPubKey(fundingTxIndex)) @@ -1215,7 +1215,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() { private fun createWallet(onChainKeys: KeyManager.SwapInOnChainKeys, amounts: List): List { return amounts.map { amount -> - val txIn = listOf(TxIn(OutPoint(randomBytes32(), 2), 0)) + val txIn = listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)) val txOut = listOf(TxOut(amount, onChainKeys.pubkeyScript), TxOut(150.sat, Script.pay2wpkh(randomKey().publicKey()))) val parentTx = Transaction(2, txIn, txOut, 0) WalletState.Utxo(parentTx, 0, 0) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/TestsHelper.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/TestsHelper.kt index 4a4816b71..1461de8f0 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/TestsHelper.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/TestsHelper.kt @@ -33,8 +33,8 @@ internal inline fun List.hasOutgoi internal inline fun List.findWatches(): List = filterIsInstance().map { it.watch }.filterIsInstance() internal inline fun List.findWatch(): T = findWatches().firstOrNull() ?: fail("cannot find watch ${T::class}") internal inline fun List.hasWatch() = assertNotNull(findWatches().firstOrNull(), "cannot find watch ${T::class}") -internal fun List.hasWatchFundingSpent(txId: ByteVector32): WatchSpent = hasWatch().also { assertEquals(txId, it.txId); assertEquals(BITCOIN_FUNDING_SPENT, it.event) } -internal fun List.hasWatchConfirmed(txId: ByteVector32): WatchConfirmed = assertNotNull(findWatches().firstOrNull { it.txId == txId }) +internal fun List.hasWatchFundingSpent(txId: TxId): WatchSpent = hasWatch().also { assertEquals(txId, it.txId); assertEquals(BITCOIN_FUNDING_SPENT, it.event) } +internal fun List.hasWatchConfirmed(txId: TxId): WatchConfirmed = assertNotNull(findWatches().firstOrNull { it.txId == txId }) // Commands internal inline fun List.findCommands(): List = filterIsInstance().map { it.command }.filterIsInstance() @@ -371,7 +371,7 @@ object TestsHelper { val paymentHash: ByteVector32 = Crypto.sha256(paymentPreimage).toByteVector32() val expiry = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight) val dummyKey = PrivateKey(ByteVector32("0101010101010101010101010101010101010101010101010101010101010101")).publicKey() - val dummyUpdate = ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId(144, 0, 0), 0, 0, 0, CltvExpiryDelta(1), 0.msat, 0.msat, 0, null) + val dummyUpdate = ChannelUpdate(ByteVector64.Zeroes, BlockHash(ByteVector32.Zeroes), ShortChannelId(144, 0, 0), 0, 0, 0, CltvExpiryDelta(1), 0.msat, 0.msat, 0, null) val cmd = OutgoingPaymentPacket.buildCommand( paymentId, paymentHash, @@ -383,7 +383,7 @@ object TestsHelper { fun createWallet(keyManager: KeyManager, amount: Satoshi): Pair> { val (privateKey, script) = keyManager.swapInOnChainWallet.run { Pair(userPrivateKey, pubkeyScript) } - val parentTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 3), 0)), listOf(TxOut(amount, script)), 0) + val parentTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 3), 0)), listOf(TxOut(amount, script)), 0) return privateKey to listOf(WalletState.Utxo(parentTx, 0, 42)) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt index 11bfd828f..9d69a8575 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt @@ -534,7 +534,7 @@ class ClosingTestsCommon : LightningTestSuite() { localCommitPublished.commitTx.txIn.first().outPoint, localCommitPublished.htlcTimeoutTxs().first().input.outPoint, ) - assertEquals(actions1.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }, watchSpent) + assertEquals(actions1.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }, watchSpent) } @Test @@ -827,7 +827,7 @@ class ClosingTestsCommon : LightningTestSuite() { remoteCommitPublished.commitTx.txIn.first().outPoint, remoteCommitPublished.claimHtlcTimeoutTxs().first().input.outPoint, ) - assertEquals(actions1.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }, watchSpent) + assertEquals(actions1.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }, watchSpent) } @Test @@ -1083,7 +1083,7 @@ class ClosingTestsCommon : LightningTestSuite() { remoteCommitPublished.claimHtlcTimeoutTxs().first().input.outPoint, remoteCommitPublished.claimHtlcTimeoutTxs().last().input.outPoint, ) - assertEquals(actions1.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }, watchSpent) + assertEquals(actions1.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }, watchSpent) } @Test @@ -1165,7 +1165,7 @@ class ClosingTestsCommon : LightningTestSuite() { assertEquals(alice3, alice4) assertEquals(actions4.findPublishTxs(), listOf(futureRemoteCommitPublished.claimMainOutputTx!!.tx)) assertEquals(actions4.findWatches().map { it.txId }, listOf(bobCommitTx.txid, futureRemoteCommitPublished.claimMainOutputTx!!.tx.txid)) - assertEquals(actions4.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }, listOf(bobCommitTx.txIn.first().outPoint)) + assertEquals(actions4.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }, listOf(bobCommitTx.txIn.first().outPoint)) actions4.doesNotHave() } @@ -1251,7 +1251,7 @@ class ClosingTestsCommon : LightningTestSuite() { addAll(revokedCommitPublished.htlcPenaltyTxs.map { it.input.outPoint }) } assertEquals(3, outputsToWatch.size) - assertEquals(outputsToWatch, aliceActions2.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }.toSet()) + assertEquals(outputsToWatch, aliceActions2.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }.toSet()) // simulate a wallet restart run { @@ -1265,7 +1265,7 @@ class ClosingTestsCommon : LightningTestSuite() { assertEquals(aliceTxs, actions3.findPublishTxs().toSet()) assertEquals(setOf(bobRevokedTx.txid, revokedCommitPublished.claimMainOutputTx!!.tx.txid), actions3.findWatches().map { it.txId }.toSet()) val watchSpent = outputsToWatch + alice3.commitments.latest.commitInput.outPoint - assertEquals(watchSpent, actions3.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }.toSet()) + assertEquals(watchSpent, actions3.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }.toSet()) } val watchConfirmed = listOf( @@ -1585,7 +1585,7 @@ class ClosingTestsCommon : LightningTestSuite() { val bobHtlcTx = Transaction( 2, listOf( - TxIn(OutPoint(Lightning.randomBytes32(), 4), listOf(), 1), // unrelated utxo (maybe used for fee bumping) + TxIn(OutPoint(TxId(Lightning.randomBytes32()), 4), listOf(), 1), // unrelated utxo (maybe used for fee bumping) bobRevokedTx.htlcTxsAndSigs[0].txinfo.tx.txIn.first(), bobRevokedTx.htlcTxsAndSigs[1].txinfo.tx.txIn.first(), bobRevokedTx.htlcTxsAndSigs[2].txinfo.tx.txIn.first(), diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt index 281c5e950..a0f011b93 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt @@ -1981,7 +1981,7 @@ class NormalTestsCommon : LightningTestSuite() { val htlcInputs = htlcPenaltyTxs.map { it.txIn.first().outPoint }.toSet() assertEquals(4, htlcInputs.size) // each htlc-penalty tx spends a different output assertEquals(5, actions2.findWatches().count { it.event is BITCOIN_OUTPUT_SPENT }) - assertEquals(htlcInputs + mainPenaltyTx.txIn.first().outPoint, actions2.findWatches().map { OutPoint(it.txId.reversed(), it.outputIndex.toLong()) }.toSet()) + assertEquals(htlcInputs + mainPenaltyTx.txIn.first().outPoint, actions2.findWatches().map { OutPoint(it.txId, it.outputIndex.toLong()) }.toSet()) // two main outputs are 760 000 and 200 000 (minus fees) assertEquals(748_070.sat, mainOutputTx.txOut[0].amount) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt index 722d19558..8241ebcc9 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt @@ -260,7 +260,7 @@ class SpliceTestsCommon : LightningTestSuite() { val (alice1, bob1) = spliceOut(alice, bob, 60_000.sat) val spliceTx = alice1.commitments.latest.localFundingStatus.signedTx!! - val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.hash))) + val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.txid))) assertEquals(actionsAlice2.size, 2) actionsAlice2.has() actionsAlice2.has() @@ -268,7 +268,7 @@ class SpliceTestsCommon : LightningTestSuite() { assertNotEquals(alice2.commitments.latest.fundingTxId, alice.commitments.latest.fundingTxId) assertIs(alice2.commitments.latest.localFundingStatus) - val (bob2, actionsBob2) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.hash))) + val (bob2, actionsBob2) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.txid))) assertEquals(actionsBob2.size, 2) actionsBob2.has() actionsBob2.has() @@ -285,7 +285,7 @@ class SpliceTestsCommon : LightningTestSuite() { val (alice2, _) = spliceOut(alice1, bob1, 60_000.sat) val spliceTx2 = alice2.commitments.latest.localFundingStatus.signedTx!! - val (_, actionsAlice3) = alice2.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx2.hash))) + val (_, actionsAlice3) = alice2.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx2.txid))) assertEquals(3, actionsAlice3.size) actionsAlice3.has() assertContains(actionsAlice3, ChannelAction.Storage.SetLocked(spliceTx1.txid)) @@ -303,10 +303,10 @@ class SpliceTestsCommon : LightningTestSuite() { val (nodes2, preimage, htlc) = addHtlc(15_000_000.msat, alice1, bob1) val (alice3, bob3) = crossSign(nodes2.first, nodes2.second, commitmentsCount = 2) - val (alice4, actionsAlice4) = alice3.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.hash))) + val (alice4, actionsAlice4) = alice3.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.txid))) actionsAlice4.has() assertEquals(alice4.commitments.active.size, 1) - val (bob4, actionsBob4) = bob3.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.hash))) + val (bob4, actionsBob4) = bob3.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.txid))) actionsBob4.has() assertEquals(bob4.commitments.active.size, 1) @@ -332,7 +332,7 @@ class SpliceTestsCommon : LightningTestSuite() { assertEquals(alice2.commitments.active.size, 3) assertEquals(bob2.commitments.active.size, 3) val spliceTx = alice2.commitments.latest.localFundingStatus.signedTx!! - val spliceLocked = SpliceLocked(alice.channelId, spliceTx.hash) + val spliceLocked = SpliceLocked(alice.channelId, spliceTx.txid) // Alice adds a new HTLC, and sends commit_sigs before receiving Bob's splice_locked. // @@ -840,10 +840,10 @@ class SpliceTestsCommon : LightningTestSuite() { val (alice, bob) = reachNormalWithConfirmedFundingTx(zeroConf = true) val (alice1, bob1) = spliceOut(alice, bob, 50_000.sat) val spliceTx = alice1.commitments.latest.localFundingStatus.signedTx!! - val (alice2, _) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.hash))) + val (alice2, _) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.txid))) assertEquals(alice2.commitments.active.size, 1) assertEquals(alice2.commitments.inactive.size, 1) - val (bob2, _) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.hash))) + val (bob2, _) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.txid))) assertEquals(bob2.commitments.active.size, 1) assertEquals(bob2.commitments.inactive.size, 1) @@ -892,11 +892,11 @@ class SpliceTestsCommon : LightningTestSuite() { val (alice, bob) = reachNormalWithConfirmedFundingTx(zeroConf = true) val (alice1, bob1) = spliceOut(alice, bob, 50_000.sat) val spliceTx = alice1.commitments.latest.localFundingStatus.signedTx!! - val (alice2, _) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.hash))) + val (alice2, _) = alice1.process(ChannelCommand.MessageReceived(SpliceLocked(alice.channelId, spliceTx.txid))) assertIs>(alice2) assertEquals(alice2.commitments.active.size, 1) assertEquals(alice2.commitments.inactive.size, 1) - val (bob2, _) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.hash))) + val (bob2, _) = bob1.process(ChannelCommand.MessageReceived(SpliceLocked(bob.channelId, spliceTx.txid))) assertIs>(bob2) assertEquals(bob2.commitments.active.size, 1) assertEquals(bob2.commitments.inactive.size, 1) @@ -1045,7 +1045,7 @@ class SpliceTestsCommon : LightningTestSuite() { return exchangeSpliceSigs(alice4, commitSigAlice, bob4, commitSigBob) } - private fun checkCommandResponse(replyTo: CompletableDeferred, parentCommitment: Commitment, spliceInit: SpliceInit): ByteVector32 = runBlocking { + private fun checkCommandResponse(replyTo: CompletableDeferred, parentCommitment: Commitment, spliceInit: SpliceInit): TxId = runBlocking { val response = replyTo.await() assertIs(response) assertEquals(response.capacity, parentCommitment.fundingAmount + spliceInit.fundingContribution) @@ -1113,7 +1113,7 @@ class SpliceTestsCommon : LightningTestSuite() { private fun createWalletWithFunds(keyManager: KeyManager, amounts: List): List { val script = keyManager.swapInOnChainWallet.pubkeyScript return amounts.map { amount -> - val txIn = listOf(TxIn(OutPoint(Lightning.randomBytes32(), 2), 0)) + val txIn = listOf(TxIn(OutPoint(TxId(Lightning.randomBytes32()), 2), 0)) val txOut = listOf(TxOut(amount, script), TxOut(150.sat, Script.pay2wpkh(randomKey().publicKey()))) val parentTx = Transaction(2, txIn, txOut, 0) WalletState.Utxo(parentTx, 0, 42) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt index d388377af..de788e393 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt @@ -1,12 +1,11 @@ package fr.acinq.lightning.channel.states -import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.Feature import fr.acinq.lightning.blockchain.* import fr.acinq.lightning.channel.* - import fr.acinq.lightning.channel.TestsHelper.reachNormal import fr.acinq.lightning.tests.TestConstants import fr.acinq.lightning.tests.utils.LightningTestSuite @@ -339,7 +338,7 @@ class SyncingTestsCommon : LightningTestSuite() { return Pair(alice, bob) } - data class UnsignedRbfFixture(val alice: LNChannel, val commitSigAlice: CommitSig, val bob: LNChannel, val commitSigBob: CommitSig, val rbfFundingTxId: ByteVector32) + data class UnsignedRbfFixture(val alice: LNChannel, val commitSigAlice: CommitSig, val bob: LNChannel, val commitSigBob: CommitSig, val rbfFundingTxId: TxId) fun createUnsignedRbf(): UnsignedRbfFixture { val (alice, bob, _, wallet) = WaitForFundingConfirmedTestsCommon.init() diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForChannelReadyTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForChannelReadyTestsCommon.kt index c931e619d..a26995701 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForChannelReadyTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForChannelReadyTestsCommon.kt @@ -10,7 +10,6 @@ import fr.acinq.lightning.channel.* import fr.acinq.lightning.tests.TestConstants import fr.acinq.lightning.tests.utils.LightningTestSuite import fr.acinq.lightning.utils.msat -import fr.acinq.lightning.utils.sat import fr.acinq.lightning.utils.toMilliSatoshi import fr.acinq.lightning.wire.* import kotlin.test.* @@ -44,7 +43,7 @@ class WaitForChannelReadyTestsCommon : LightningTestSuite() { @Test fun `recv TxSignatures -- duplicate`() { val (alice, _, _, _) = init() - val (alice1, actions1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, alice.commitments.latest.fundingTxId.reversed(), listOf()))) + val (alice1, actions1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, alice.commitments.latest.fundingTxId, listOf()))) assertEquals(alice1, alice) assertTrue(actions1.isEmpty()) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt index ca278662e..f74414982 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt @@ -444,7 +444,7 @@ class WaitForFundingConfirmedTestsCommon : LightningTestSuite() { assertIs(previousFundingTx) // Alice adds a new input that increases her contribution and covers the additional fees. val script = alice.staticParams.nodeParams.keyManager.swapInOnChainWallet.pubkeyScript - val parentTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 1), 0)), listOf(TxOut(30_000.sat, script)), 0) + val parentTx = Transaction(2, listOf(TxIn(OutPoint(TxId(randomBytes32()), 1), 0)), listOf(TxOut(30_000.sat, script)), 0) val wallet1 = wallet + listOf(WalletState.Utxo(parentTx, 0, 42)) return ChannelCommand.Funding.BumpFundingFee(previousFundingTx.feerate * 1.1, previousFundingParams.localContribution + 20_000.sat, wallet1, previousFundingTx.tx.lockTime + 1) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt index 79a93d151..2ae04aa62 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt @@ -1,9 +1,6 @@ package fr.acinq.lightning.channel.states -import fr.acinq.bitcoin.ByteVector32 -import fr.acinq.bitcoin.ByteVector64 -import fr.acinq.bitcoin.Satoshi -import fr.acinq.bitcoin.Script +import fr.acinq.bitcoin.* import fr.acinq.lightning.Feature import fr.acinq.lightning.Features import fr.acinq.lightning.Lightning.randomBytes32 @@ -205,12 +202,12 @@ class WaitForFundingCreatedTestsCommon : LightningTestSuite() { fun `recv TxSignatures`() { val (alice, bob, _) = init(ChannelType.SupportedChannelType.AnchorOutputs, bobFundingAmount = 0.sat, alicePushAmount = 0.msat) run { - val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, randomBytes32(), listOf()))) + val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, TxId(randomBytes32()), listOf()))) assertEquals(actionsAlice1.findOutgoingMessage().toAscii(), UnexpectedFundingSignatures(alice.channelId).message) assertIs(alice1.state) } run { - val (bob1, actionsBob1) = bob.process(ChannelCommand.MessageReceived(TxSignatures(bob.channelId, randomBytes32(), listOf()))) + val (bob1, actionsBob1) = bob.process(ChannelCommand.MessageReceived(TxSignatures(bob.channelId, TxId(randomBytes32()), listOf()))) assertEquals(actionsBob1.findOutgoingMessage().toAscii(), UnexpectedFundingSignatures(bob.channelId).message) assertIs(bob1.state) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt index b11c490c9..faf65e15e 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt @@ -182,12 +182,12 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { fun `recv TxSignatures -- before CommitSig`() { val (alice, _, bob, _) = init() run { - val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, randomBytes32(), listOf()))) + val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(TxSignatures(alice.channelId, TxId(randomBytes32()), listOf()))) assertEquals(actionsAlice1.findOutgoingMessage().toAscii(), UnexpectedFundingSignatures(alice.channelId).message) assertIs(alice1.state) } run { - val (bob1, actionsBob1) = bob.process(ChannelCommand.MessageReceived(TxSignatures(bob.channelId, randomBytes32(), listOf()))) + val (bob1, actionsBob1) = bob.process(ChannelCommand.MessageReceived(TxSignatures(bob.channelId, TxId(randomBytes32()), listOf()))) assertEquals(actionsBob1.findOutgoingMessage().toAscii(), UnexpectedFundingSignatures(bob.channelId).message) assertIs(bob1.state) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/db/InMemoryPaymentsDb.kt b/src/commonTest/kotlin/fr/acinq/lightning/db/InMemoryPaymentsDb.kt index fac6e0859..fcfe88949 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/db/InMemoryPaymentsDb.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/db/InMemoryPaymentsDb.kt @@ -2,7 +2,7 @@ package fr.acinq.lightning.db import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.Crypto -import fr.acinq.lightning.MilliSatoshi +import fr.acinq.bitcoin.TxId import fr.acinq.lightning.channel.ChannelException import fr.acinq.lightning.payment.FinalFailure import fr.acinq.lightning.payment.OutgoingPaymentFailure @@ -15,7 +15,7 @@ class InMemoryPaymentsDb : PaymentsDb { private val incoming = mutableMapOf() private val outgoing = mutableMapOf() private val outgoingParts = mutableMapOf>() - override suspend fun setLocked(txId: ByteVector32) {} + override suspend fun setLocked(txId: TxId) {} override suspend fun addIncomingPayment(preimage: ByteVector32, origin: IncomingPayment.Origin, createdAt: Long): IncomingPayment { val paymentHash = Crypto.sha256(preimage).toByteVector32() @@ -68,7 +68,7 @@ class InMemoryPaymentsDb : PaymentsDb { override suspend fun addOutgoingPayment(outgoingPayment: OutgoingPayment) { require(!outgoing.contains(outgoingPayment.id)) { "an outgoing payment with id=${outgoingPayment.id} already exists" } - when(outgoingPayment) { + when (outgoingPayment) { is LightningOutgoingPayment -> { outgoingPayment.parts.forEach { require(!outgoingParts.contains(it.id)) { "an outgoing payment part with id=${it.id} already exists" } } outgoing[outgoingPayment.id] = outgoingPayment.copy(parts = listOf()) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt index e9012f2bf..4f45b4673 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt @@ -70,7 +70,7 @@ class PaymentsDbTestsCommon : LightningTestSuite() { pr.paymentHash, listOf( IncomingPayment.ReceivedWith.LightningPayment(amount = 57_000.msat, channelId = channelId1, htlcId = 1L), IncomingPayment.ReceivedWith.LightningPayment(amount = 43_000.msat, channelId = channelId2, htlcId = 54L), - IncomingPayment.ReceivedWith.NewChannel(amount = 99_000.msat, channelId = channelId3, serviceFee = 1_000.msat, miningFee = 0.sat, txId = randomBytes32(), confirmedAt = null, lockedAt = null) + IncomingPayment.ReceivedWith.NewChannel(amount = 99_000.msat, channelId = channelId3, serviceFee = 1_000.msat, miningFee = 0.sat, txId = TxId(randomBytes32()), confirmedAt = null, lockedAt = null) ), 110 ) val received = db.getIncomingPayment(pr.paymentHash) @@ -146,7 +146,7 @@ class PaymentsDbTestsCommon : LightningTestSuite() { serviceFee = 15_000.msat, miningFee = 0.sat, channelId = randomBytes32(), - txId = randomBytes32(), + txId = TxId(randomBytes32()), confirmedAt = null, lockedAt = null ) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt index 179d890de..49e8cf71c 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt @@ -7,8 +7,6 @@ import fr.acinq.lightning.Lightning.randomBytes32 import fr.acinq.lightning.MilliSatoshi import fr.acinq.lightning.ShortChannelId import fr.acinq.lightning.channel.* -import fr.acinq.lightning.channel.ChannelAction -import fr.acinq.lightning.channel.ChannelCommand import fr.acinq.lightning.crypto.sphinx.Sphinx import fr.acinq.lightning.db.InMemoryPaymentsDb import fr.acinq.lightning.db.IncomingPayment @@ -175,7 +173,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { serviceFee = payToOpenRequest.payToOpenFeeSatoshis.toMilliSatoshi(), miningFee = 0.sat, localInputs = emptySet(), - txId = randomBytes32(), + txId = TxId(randomBytes32()), origin = Origin.PayToOpenOrigin(amount = payToOpenRequest.amountMsat, paymentHash = payToOpenRequest.paymentHash, serviceFee = 0.msat, miningFee = payToOpenRequest.payToOpenFeeSatoshis) ) paymentHandler.process(channelId, amountOrigin) @@ -242,7 +240,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { fun `receive pay-to-open payment with an unknown payment hash`() = runSuspendTest { val (paymentHandler, _, _) = createFixture(defaultAmount) val payToOpenRequest = PayToOpenRequest( - chainHash = ByteVector32.Zeroes, + chainHash = BlockHash(ByteVector32.Zeroes), fundingSatoshis = 100_000.sat, amountMsat = defaultAmount, payToOpenMinAmountMsat = 1_000_000.msat, @@ -337,7 +335,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { NodeHop(TestConstants.Alice.nodeParams.nodeId, TestConstants.Bob.nodeParams.nodeId, CltvExpiryDelta(144), 0.msat) ) val payToOpenRequest = PayToOpenRequest( - chainHash = ByteVector32.Zeroes, + chainHash = BlockHash(ByteVector32.Zeroes), fundingSatoshis = 100_000.sat, amountMsat = defaultAmount, payToOpenMinAmountMsat = 1_000_000.msat, @@ -1067,7 +1065,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { ) paymentHandler.db.receivePayment( paidInvoice.paymentHash, - receivedWith = listOf(IncomingPayment.ReceivedWith.NewChannel(amount = 15_000_000.msat, serviceFee = 1_000_000.msat, miningFee = 0.sat, channelId = randomBytes32(), txId = randomBytes32(), confirmedAt = null, lockedAt = null)), + receivedWith = listOf(IncomingPayment.ReceivedWith.NewChannel(amount = 15_000_000.msat, serviceFee = 1_000_000.msat, miningFee = 0.sat, channelId = randomBytes32(), txId = TxId(randomBytes32()), confirmedAt = null, lockedAt = null)), receivedAt = 101 ) // simulate incoming payment being paid before it expired @@ -1097,7 +1095,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { val dummyKey = PrivateKey(ByteVector32("0101010101010101010101010101010101010101010101010101010101010101")).publicKey() val dummyUpdate = ChannelUpdate( signature = ByteVector64.Zeroes, - chainHash = ByteVector32.Zeroes, + chainHash = BlockHash(ByteVector32.Zeroes), shortChannelId = ShortChannelId(144, 0, 0), timestampSeconds = 0, messageFlags = 0, @@ -1160,7 +1158,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { private fun makeReceivedWithNewChannel(payToOpen: PayToOpenRequest, feeRatio: Double = 0.1): IncomingPayment.ReceivedWith.NewChannel { val fee = payToOpen.amountMsat * feeRatio - return IncomingPayment.ReceivedWith.NewChannel(amount = payToOpen.amountMsat - fee, serviceFee = fee, miningFee = 0.sat, channelId = randomBytes32(), txId = randomBytes32(), confirmedAt = null, lockedAt = null) + return IncomingPayment.ReceivedWith.NewChannel(amount = payToOpen.amountMsat - fee, serviceFee = fee, miningFee = 0.sat, channelId = randomBytes32(), txId = TxId(randomBytes32()), confirmedAt = null, lockedAt = null) } private suspend fun checkDbPayment(incomingPayment: IncomingPayment, db: IncomingPaymentsDb) { diff --git a/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt index 38f61c079..d5324e6db 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt @@ -67,7 +67,7 @@ class TransactionsTestsCommon : LightningTestSuite() { private val remotePaymentPriv = PrivateKey(randomBytes32()) private val localHtlcPriv = PrivateKey(randomBytes32()) private val remoteHtlcPriv = PrivateKey(randomBytes32()) - private val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) + private val commitInput = Funding.makeFundingInputInfo(TxId(randomBytes32()), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) private val toLocalDelay = CltvExpiryDelta(144) private val localDustLimit = 546.sat private val feerate = FeeratePerKw(22_000.sat) @@ -120,7 +120,7 @@ class TransactionsTestsCommon : LightningTestSuite() { // ClaimHtlcDelayedTx // first we create a fake htlcSuccessOrTimeoutTx tx, containing only the output that will be spent by the ClaimDelayedOutputTx val pubKeyScript = write(pay2wsh(toLocalDelayed(localRevocationPriv.publicKey(), toLocalDelay, localPaymentPriv.publicKey()))) - val htlcSuccessOrTimeoutTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(ByteVector32.Zeroes, 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(20000.sat, pubKeyScript)), lockTime = 0) + val htlcSuccessOrTimeoutTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(20000.sat, pubKeyScript)), lockTime = 0) val claimHtlcDelayedTx = makeClaimLocalDelayedOutputTx(htlcSuccessOrTimeoutTx, localDustLimit, localRevocationPriv.publicKey(), toLocalDelay, localPaymentPriv.publicKey(), finalPubKeyScript, feeratePerKw) assertTrue(claimHtlcDelayedTx is Success, "is $claimHtlcDelayedTx") // we use dummy signatures to compute the weight @@ -132,7 +132,7 @@ class TransactionsTestsCommon : LightningTestSuite() { // MainPenaltyTx // first we create a fake commitTx tx, containing only the output that will be spent by the MainPenaltyTx val pubKeyScript = write(pay2wsh(toLocalDelayed(localRevocationPriv.publicKey(), toLocalDelay, localPaymentPriv.publicKey()))) - val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(ByteVector32.Zeroes, 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(20000.sat, pubKeyScript)), lockTime = 0) + val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(20000.sat, pubKeyScript)), lockTime = 0) val mainPenaltyTx = makeMainPenaltyTx(commitTx, localDustLimit, localRevocationPriv.publicKey(), finalPubKeyScript, toLocalDelay, localPaymentPriv.publicKey(), feeratePerKw) assertTrue(mainPenaltyTx is Success, "is $mainPenaltyTx") // we use dummy signatures to compute the weight @@ -147,7 +147,7 @@ class TransactionsTestsCommon : LightningTestSuite() { val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000).msat, ByteVector32(sha256(paymentPreimage)), CltvExpiryDelta(144).toCltvExpiry(blockHeight.toLong()), TestConstants.emptyOnionPacket) val redeemScript = htlcReceived(localHtlcPriv.publicKey(), remoteHtlcPriv.publicKey(), localRevocationPriv.publicKey(), ripemd160(htlc.paymentHash), htlc.cltvExpiry) val pubKeyScript = write(pay2wsh(redeemScript)) - val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(ByteVector32.Zeroes, 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(htlc.amountMsat.truncateToSatoshi(), pubKeyScript)), lockTime = 0) + val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 0), TxIn.SEQUENCE_FINAL)), txOut = listOf(TxOut(htlc.amountMsat.truncateToSatoshi(), pubKeyScript)), lockTime = 0) val htlcPenaltyTx = makeHtlcPenaltyTx(commitTx, 0, write(redeemScript), localDustLimit, finalPubKeyScript, feeratePerKw) assertTrue(htlcPenaltyTx is Success, "is $htlcPenaltyTx") // we use dummy signatures to compute the weight @@ -175,7 +175,7 @@ class TransactionsTestsCommon : LightningTestSuite() { remoteHtlcPriv.publicKey(), spec ) - val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(ByteVector32.Zeroes, 0), TxIn.SEQUENCE_FINAL)), txOut = outputs.map { it.output }, lockTime = 0) + val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 0), TxIn.SEQUENCE_FINAL)), txOut = outputs.map { it.output }, lockTime = 0) val claimHtlcSuccessTx = makeClaimHtlcSuccessTx(commitTx, outputs, localDustLimit, remoteHtlcPriv.publicKey(), localHtlcPriv.publicKey(), localRevocationPriv.publicKey(), finalPubKeyScript, htlc, feeratePerKw) assertTrue(claimHtlcSuccessTx is Success, "is $claimHtlcSuccessTx") @@ -204,7 +204,7 @@ class TransactionsTestsCommon : LightningTestSuite() { remoteHtlcPriv.publicKey(), spec ) - val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(ByteVector32.Zeroes, 0), TxIn.SEQUENCE_FINAL)), txOut = outputs.map { it.output }, lockTime = 0) + val commitTx = Transaction(version = 0, txIn = listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 0), TxIn.SEQUENCE_FINAL)), txOut = outputs.map { it.output }, lockTime = 0) val claimHtlcTimeoutTx = makeClaimHtlcTimeoutTx(commitTx, outputs, localDustLimit, remoteHtlcPriv.publicKey(), localHtlcPriv.publicKey(), localRevocationPriv.publicKey(), finalPubKeyScript, htlc, feeratePerKw) assertTrue(claimHtlcTimeoutTx is Success, "is $claimHtlcTimeoutTx") @@ -218,7 +218,7 @@ class TransactionsTestsCommon : LightningTestSuite() { @Test fun `generate valid commitment and htlc transactions`() { val finalPubKeyScript = write(pay2wpkh(PrivateKey(ByteVector32("01".repeat(32))).publicKey())) - val commitInput = Funding.makeFundingInputInfo(ByteVector32("02".repeat(32)), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) + val commitInput = Funding.makeFundingInputInfo(TxId(ByteVector32("02".repeat(32))), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) // htlc1 and htlc2 are regular IN/OUT htlcs val paymentPreimage1 = ByteVector32("03".repeat(32)) @@ -446,7 +446,7 @@ class TransactionsTestsCommon : LightningTestSuite() { val userWallet = TestConstants.Alice.keyManager.swapInOnChainWallet val swapInTx = Transaction( version = 2, - txIn = listOf(TxIn(OutPoint(randomBytes32(), 2), 0)), + txIn = listOf(TxIn(OutPoint(TxId(randomBytes32()), 2), 0)), txOut = listOf(TxOut(100_000.sat, userWallet.pubkeyScript)), lockTime = 0 ) @@ -485,10 +485,10 @@ class TransactionsTestsCommon : LightningTestSuite() { val pubkey = randomKey().publicKey() // DER-encoded ECDSA signatures usually take up to 72 bytes. val sig = randomBytes(72).toByteVector() - val tx = Transaction(2, listOf(TxIn(OutPoint(ByteVector32.Zeroes, 2), 0)), listOf(TxOut(50_000.sat, pay2wpkh(pubkey))), 0) + val tx = Transaction(2, listOf(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 2), 0)), listOf(TxOut(50_000.sat, pay2wpkh(pubkey))), 0) val redeemScript = Scripts.swapIn2of2(pubkey, pubkey, 144) val witness = ScriptWitness(listOf(sig, sig, write(redeemScript).byteVector())) - val swapInput = TxIn(OutPoint(ByteVector32.Zeroes, 3), ByteVector.empty, 0, witness) + val swapInput = TxIn(OutPoint(TxId(ByteVector32.Zeroes), 3), ByteVector.empty, 0, witness) val txWithAdditionalInput = tx.copy(txIn = tx.txIn + listOf(swapInput)) val inputWeight = txWithAdditionalInput.weight() - tx.weight() assertEquals(inputWeight, swapInputWeight) @@ -504,7 +504,7 @@ class TransactionsTestsCommon : LightningTestSuite() { val remotePaymentPriv = PrivateKey.fromHex("a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6") val localHtlcPriv = PrivateKey.fromHex("a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7") val remoteHtlcPriv = PrivateKey.fromHex("a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8") - val commitInput = Funding.makeFundingInputInfo(ByteVector32.fromValidHex("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0"), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) + val commitInput = Funding.makeFundingInputInfo(TxId("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0"), 0, 1.btc, localFundingPriv.publicKey(), remoteFundingPriv.publicKey()) // htlc1 and htlc2 are two regular incoming HTLCs with different amounts. // htlc2 and htlc3 have the same amounts and should be sorted according to their scriptPubKey diff --git a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt index 0b25c5bce..aba3f0b89 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt @@ -277,7 +277,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { @Test fun `encode - decode open_channel`() { // @formatter:off - val defaultOpen = OpenDualFundedChannel(ByteVector32.Zeroes, ByteVector32.One, FeeratePerKw(5000.sat), FeeratePerKw(4000.sat), 250_000.sat, 500.sat, 50_000, 15.msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), 1.toByte()) + val defaultOpen = OpenDualFundedChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.One, FeeratePerKw(5000.sat), FeeratePerKw(4000.sat), 250_000.sat, 500.sat, 50_000, 15.msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), 1.toByte()) val defaultEncoded = ByteVector("0040 0000000000000000000000000000000000000000000000000000000000000000 0100000000000000000000000000000000000000000000000000000000000000 00001388 00000fa0 000000000003d090 00000000000001f4 000000000000c350 000000000000000f 0090 01e3 0009eb10 031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f 024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766 02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337 03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b 0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7 03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a 02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f 01") val testCases = listOf( defaultOpen to defaultEncoded, @@ -401,7 +401,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { @Test fun `encode - decode splice messages`() { val channelId = ByteVector32("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") - val fundingTxHash = ByteVector32("24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566") + val fundingTxId = TxId(TxHash("24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566")) val fundingPubkey = PublicKey(ByteVector.fromHex("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")) val testCases = listOf( // @formatter:off @@ -413,7 +413,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { SpliceAck(channelId, 40_000.sat, 10_000_000.msat, fundingPubkey) to ByteVector("908a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000009c40 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 fe4700000703989680"), SpliceAck(channelId, 0.sat, fundingPubkey) to ByteVector("908a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000000 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), SpliceAck(channelId, (-25_000).sat, fundingPubkey) to ByteVector("908a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ffffffffffff9e58 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), - SpliceLocked(channelId, fundingTxHash) to ByteVector("908c aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566"), + SpliceLocked(channelId, fundingTxId) to ByteVector("908c aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566"), // @formatter:on ) testCases.forEach { (message, bin) -> @@ -430,11 +430,11 @@ class LightningCodecsTestsCommon : LightningTestSuite() { val channelId = ByteVector32("c11b8fbd682b3c6ee11f9d7268e22bb5887cd4d3bf3338bfcc340583f685733c") val commitmentSecret = PrivateKey.fromHex("34f159d37cf7b5de52ec0adc3968886232f90d272e8c82e8b6f7fcb7e57c4b55") val commitmentPoint = PublicKey.fromHex("02bf050efff417efc09eb211ca9e4e845920e2503740800e88505b25e6f0e1e867") - val fundingTxHash = ByteVector32("24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566") + val fundingTxId = TxId(TxHash("24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566")) val testCases = listOf( // @formatter:off ChannelReestablish(channelId, 242842, 42, commitmentSecret, commitmentPoint) to ByteVector("0088 c11b8fbd682b3c6ee11f9d7268e22bb5887cd4d3bf3338bfcc340583f685733c 000000000003b49a 000000000000002a 34f159d37cf7b5de52ec0adc3968886232f90d272e8c82e8b6f7fcb7e57c4b55 02bf050efff417efc09eb211ca9e4e845920e2503740800e88505b25e6f0e1e867"), - ChannelReestablish(channelId, 242842, 42, commitmentSecret, commitmentPoint, TlvStream(ChannelReestablishTlv.NextFunding(fundingTxHash))) to ByteVector("0088 c11b8fbd682b3c6ee11f9d7268e22bb5887cd4d3bf3338bfcc340583f685733c 000000000003b49a 000000000000002a 34f159d37cf7b5de52ec0adc3968886232f90d272e8c82e8b6f7fcb7e57c4b55 02bf050efff417efc09eb211ca9e4e845920e2503740800e88505b25e6f0e1e867 00 20 24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566") + ChannelReestablish(channelId, 242842, 42, commitmentSecret, commitmentPoint, TlvStream(ChannelReestablishTlv.NextFunding(fundingTxId))) to ByteVector("0088 c11b8fbd682b3c6ee11f9d7268e22bb5887cd4d3bf3338bfcc340583f685733c 000000000003b49a 000000000000002a 34f159d37cf7b5de52ec0adc3968886232f90d272e8c82e8b6f7fcb7e57c4b55 02bf050efff417efc09eb211ca9e4e845920e2503740800e88505b25e6f0e1e867 00 20 24e1b2c94c4e734dd5b9c5f3c910fbb6b3b436ced6382c7186056a5a23f14566") // @formatter:on ) testCases.forEach { (message, bin) -> @@ -450,7 +450,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { fun `encode - decode channel_update`() { val channelUpdate = ChannelUpdate( randomBytes64(), - randomBytes32(), + BlockHash(randomBytes32()), ShortChannelId(561), 1105, 0, @@ -474,7 +474,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { val decoded = LightningMessage.decode(encoded.toByteArray()) val expected = ChannelUpdate( ByteVector64("58fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf17923"), - ByteVector32("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), + BlockHash("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), ShortChannelId(0x5a10000020000L), 1539791129, 1, @@ -494,7 +494,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { fun `encode - decode channel_update with unknown trailing bytes`() { val channelUpdate = ChannelUpdate( randomBytes64(), - randomBytes32(), + BlockHash(randomBytes32()), ShortChannelId(561), 1105, 0, @@ -520,7 +520,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { randomBytes64(), randomBytes64(), Features(Hex.decode("09004200")), - randomBytes32(), + BlockHash(randomBytes32()), ShortChannelId(42), randomKey().publicKey(), randomKey().publicKey(), @@ -533,7 +533,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { randomBytes64(), randomBytes64(), Features(mapOf()), - randomBytes32(), + BlockHash(randomBytes32()), ShortChannelId(42), randomKey().publicKey(), randomKey().publicKey(), @@ -602,7 +602,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { @Test fun `nonreg backup channel data`() { val channelId = randomBytes32() - val txHash = randomBytes32() + val txHash = TxHash(randomBytes32()) val signature = randomBytes64() val key = randomKey() val point = randomKey().publicKey() @@ -618,10 +618,10 @@ class LightningCodecsTestsCommon : LightningTestSuite() { Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("fe47010000 07 bbbbbbbbbbbbbb") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point).withChannelData(ByteVector("bbbbbbbbbbbbbb")), Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") + Hex.decode("fe47010000 07 bbbbbbbbbbbbbb") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(setOf(ChannelReestablishTlv.ChannelData(EncryptedChannelData(ByteVector("bbbbbbbbbbbbbb")))), setOf(GenericTlv(1, ByteVector("0102"))))), // tx_signatures - Hex.decode("0047") + channelId.toByteArray() + txHash.toByteArray() + Hex.decode("0000") to TxSignatures(channelId, txHash, listOf()), - Hex.decode("0047") + channelId.toByteArray() + txHash.toByteArray() + Hex.decode("0000 fe47010000 00") to TxSignatures(channelId, txHash, listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0047") + channelId.toByteArray() + txHash.toByteArray() + Hex.decode("0000 fe47010000 04 deadbeef") to TxSignatures(channelId, txHash, listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef"))))), - Hex.decode("0047") + channelId.toByteArray() + txHash.toByteArray() + Hex.decode("0000 2b012a fe47010000 04 deadbeef") to TxSignatures(channelId, txHash, listOf(), TlvStream(setOf(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef")))), setOf(GenericTlv(43, ByteVector("2a"))))), + Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000") to TxSignatures(channelId, TxId(txHash), listOf()), + Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 fe47010000 00") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData.empty))), + Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 fe47010000 04 deadbeef") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef"))))), + Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 2b012a fe47010000 04 deadbeef") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(setOf(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef")))), setOf(GenericTlv(43, ByteVector("2a"))))), // commit_sig Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000") to CommitSig(channelId, signature, listOf()), Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000") + Hex.decode("01 02 0102") to CommitSig(channelId, signature, listOf(), TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), @@ -668,7 +668,7 @@ class LightningCodecsTestsCommon : LightningTestSuite() { val aboveLimit = EncryptedChannelData(ByteVector(ByteArray(60000) { 42 })) val messages = listOf( ChannelReestablish(randomBytes32(), 0, 0, randomKey(), randomKey().publicKey()), - TxSignatures(randomBytes32(), randomBytes32(), listOf()), + TxSignatures(randomBytes32(), TxId(randomBytes32()), listOf()), CommitSig(randomBytes32(), randomBytes64(), listOf()), RevokeAndAck(randomBytes32(), randomKey(), randomKey().publicKey()), Shutdown(randomBytes32(), ByteVector("deadbeef")), @@ -692,10 +692,10 @@ class LightningCodecsTestsCommon : LightningTestSuite() { @Test fun `encode - decode pay-to-open messages`() { val testCases = listOf( - PayToOpenRequest(randomBytes32(), 10_000.sat, 5_000.msat, 100.msat, 10.sat, randomBytes32(), 100, OnionRoutingPacket(0, randomKey().publicKey().value, ByteVector("0102030405"), randomBytes32())), - PayToOpenResponse(randomBytes32(), randomBytes32(), PayToOpenResponse.Result.Success(randomBytes32())), - PayToOpenResponse(randomBytes32(), randomBytes32(), PayToOpenResponse.Result.Failure(null)), - PayToOpenResponse(randomBytes32(), randomBytes32(), PayToOpenResponse.Result.Failure(ByteVector("deadbeef"))), + PayToOpenRequest(BlockHash(randomBytes32()), 10_000.sat, 5_000.msat, 100.msat, 10.sat, randomBytes32(), 100, OnionRoutingPacket(0, randomKey().publicKey().value, ByteVector("0102030405"), randomBytes32())), + PayToOpenResponse(BlockHash(randomBytes32()), randomBytes32(), PayToOpenResponse.Result.Success(randomBytes32())), + PayToOpenResponse(BlockHash(randomBytes32()), randomBytes32(), PayToOpenResponse.Result.Failure(null)), + PayToOpenResponse(BlockHash(randomBytes32()), randomBytes32(), PayToOpenResponse.Result.Failure(ByteVector("deadbeef"))), ) testCases.forEach { @@ -712,8 +712,8 @@ class LightningCodecsTestsCommon : LightningTestSuite() { // @formatter:off PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710"), PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000, TlvStream(PleaseOpenChannelTlv.GrandParents(listOf()))) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710 fd023100"), - PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000, TlvStream(PleaseOpenChannelTlv.GrandParents(listOf(OutPoint(ByteVector32("d0556c8cc004933f40b9ca5e87e18cb549298fb02d7e64b0c0ee95303485145a"), 5))))) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710 fd023128d0556c8cc004933f40b9ca5e87e18cb549298fb02d7e64b0c0ee95303485145a0000000000000005"), - PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000, TlvStream(PleaseOpenChannelTlv.GrandParents(listOf(OutPoint(ByteVector32("572b045edb5f0e3ff667e914e368273b11a874fae56a735b332b54048b7978c2"), 0), OutPoint(ByteVector32("cd6ac843158a1c317021de1323cdd2071f0f59744f79b298a8a45fda2dd7989f"), 1105))))) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710 fd023150572b045edb5f0e3ff667e914e368273b11a874fae56a735b332b54048b7978c20000000000000000cd6ac843158a1c317021de1323cdd2071f0f59744f79b298a8a45fda2dd7989f0000000000000451"), + PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000, TlvStream(PleaseOpenChannelTlv.GrandParents(listOf(OutPoint(TxHash("d0556c8cc004933f40b9ca5e87e18cb549298fb02d7e64b0c0ee95303485145a"), 5))))) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710 fd023128d0556c8cc004933f40b9ca5e87e18cb549298fb02d7e64b0c0ee95303485145a0000000000000005"), + PleaseOpenChannel(Block.RegtestGenesisBlock.hash, ByteVector32("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25"), 123_456.sat, 2, 522_000, TlvStream(PleaseOpenChannelTlv.GrandParents(listOf(OutPoint(TxHash("572b045edb5f0e3ff667e914e368273b11a874fae56a735b332b54048b7978c2"), 0), OutPoint(TxHash("cd6ac843158a1c317021de1323cdd2071f0f59744f79b298a8a45fda2dd7989f"), 1105))))) to Hex.decode("8ca1 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db25 000000000001e240 0002 0007f710 fd023150572b045edb5f0e3ff667e914e368273b11a874fae56a735b332b54048b7978c20000000000000000cd6ac843158a1c317021de1323cdd2071f0f59744f79b298a8a45fda2dd7989f0000000000000451"), // @formatter:on )