diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala index 86c0ec0162..e015c773ac 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala @@ -24,7 +24,7 @@ import akka.pattern._ import akka.util.Timeout import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, Satoshi, Script, addressToPublicKeyScript} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, ByteVector64, Crypto, OutPoint, Satoshi, Script, TxId, addressToPublicKeyScript} import fr.acinq.eclair.ApiTypes.ChannelNotFound import fr.acinq.eclair.balance.CheckBalance.GlobalBalance import fr.acinq.eclair.balance.{BalanceActor, ChannelsListener} @@ -58,7 +58,7 @@ import java.util.UUID import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future, Promise} -case class GetInfoResponse(version: String, nodeId: PublicKey, alias: String, color: String, features: Features[Feature], chainHash: ByteVector32, network: String, blockHeight: Int, publicAddresses: Seq[NodeAddress], onionAddress: Option[NodeAddress], instanceId: String) +case class GetInfoResponse(version: String, nodeId: PublicKey, alias: String, color: String, features: Features[Feature], chainHash: BlockHash, network: String, blockHeight: Int, publicAddresses: Seq[NodeAddress], onionAddress: Option[NodeAddress], instanceId: String) case class AuditResponse(sent: Seq[PaymentSent], received: Seq[PaymentReceived], relayed: Seq[PaymentRelayed]) @@ -131,9 +131,9 @@ trait Eclair { def sentInfo(id: PaymentIdentifier)(implicit timeout: Timeout): Future[Seq[OutgoingPayment]] - def sendOnChain(address: String, amount: Satoshi, confirmationTargetOrFeerate: Either[Long, FeeratePerByte]): Future[ByteVector32] + def sendOnChain(address: String, amount: Satoshi, confirmationTargetOrFeerate: Either[Long, FeeratePerByte]): Future[TxId] - def cpfpBumpFees(targetFeeratePerByte: FeeratePerByte, outpoints: Set[OutPoint]): Future[ByteVector32] + def cpfpBumpFees(targetFeeratePerByte: FeeratePerByte, outpoints: Set[OutPoint]): Future[TxId] def findRoute(targetNodeId: PublicKey, amount: MilliSatoshi, pathFindingExperimentName_opt: Option[String], extraEdges: Seq[Invoice.ExtraEdge] = Seq.empty, includeLocalChannelCost: Boolean = false, ignoreNodeIds: Seq[PublicKey] = Seq.empty, ignoreShortChannelIds: Seq[ShortChannelId] = Seq.empty, maxFee_opt: Option[MilliSatoshi] = None)(implicit timeout: Timeout): Future[RouteResponse] @@ -357,7 +357,7 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging { } } - override def sendOnChain(address: String, amount: Satoshi, confirmationTargetOrFeerate: Either[Long, FeeratePerByte]): Future[ByteVector32] = { + override def sendOnChain(address: String, amount: Satoshi, confirmationTargetOrFeerate: Either[Long, FeeratePerByte]): Future[TxId] = { val feeRate = confirmationTargetOrFeerate match { case Left(blocks) => if (blocks < 3) appKit.nodeParams.currentFeerates.fast @@ -375,7 +375,7 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging { } } - override def cpfpBumpFees(targetFeeratePerByte: FeeratePerByte, outpoints: Set[OutPoint]): Future[ByteVector32] = { + override def cpfpBumpFees(targetFeeratePerByte: FeeratePerByte, outpoints: Set[OutPoint]): Future[TxId] = { appKit.wallet match { case w: BitcoinCoreClient => w.cpfp(outpoints, FeeratePerKw(targetFeeratePerByte)).map(_.txid) case _ => Future.failed(new IllegalArgumentException("this call is only available with a bitcoin core backend")) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index 94cca6734d..90e108e96c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair import com.typesafe.config.{Config, ConfigFactory, ConfigValueType} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, Crypto, Satoshi} import fr.acinq.eclair.Setup.Seeds import fr.acinq.eclair.blockchain.fee._ import fr.acinq.eclair.channel.ChannelFlags @@ -73,7 +73,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager, autoReconnect: Boolean, initialRandomReconnectDelay: FiniteDuration, maxReconnectInterval: FiniteDuration, - chainHash: ByteVector32, + chainHash: BlockHash, invoiceExpiry: FiniteDuration, multiPartPaymentExpiry: FiniteDuration, peerConnectionConf: PeerConnection.Conf, @@ -184,16 +184,16 @@ object NodeParams extends Logging { Seeds(nodeSeed, channelSeed) } - private val chain2Hash: Map[String, ByteVector32] = Map( + private val chain2Hash: Map[String, BlockHash] = Map( "regtest" -> Block.RegtestGenesisBlock.hash, "testnet" -> Block.TestnetGenesisBlock.hash, "signet" -> Block.SignetGenesisBlock.hash, "mainnet" -> Block.LivenetGenesisBlock.hash ) - def hashFromChain(chain: String): ByteVector32 = chain2Hash.getOrElse(chain, throw new RuntimeException(s"invalid chain '$chain'")) + def hashFromChain(chain: String): BlockHash = chain2Hash.getOrElse(chain, throw new RuntimeException(s"invalid chain '$chain'")) - def chainFromHash(chainHash: ByteVector32): String = chain2Hash.map(_.swap).getOrElse(chainHash, throw new RuntimeException(s"invalid chainHash '$chainHash'")) + def chainFromHash(chainHash: BlockHash): String = chain2Hash.map(_.swap).getOrElse(chainHash, throw new RuntimeException(s"invalid chainHash '$chainHash'")) def parseSocks5ProxyParams(config: Config): Option[Socks5ProxyParams] = { if (config.getBoolean("socks5.enabled")) { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index d04a5105f5..ab04b5f70b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -23,7 +23,7 @@ import akka.actor.{ActorRef, ActorSystem, Props, SupervisorStrategy, typed} import akka.pattern.after import akka.util.Timeout import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BlockId, ByteVector32, Satoshi} import fr.acinq.eclair.Setup.Seeds import fr.acinq.eclair.balance.{BalanceActor, ChannelsListener} import fr.acinq.eclair.blockchain._ @@ -134,7 +134,7 @@ class Setup(val datadir: File, case "password" => BitcoinJsonRPCAuthMethod.UserPassword(config.getString("bitcoind.rpcuser"), config.getString("bitcoind.rpcpassword")) } - case class BitcoinStatus(version: Int, chainHash: ByteVector32, initialBlockDownload: Boolean, verificationProgress: Double, blockCount: Long, headerCount: Long, unspentAddresses: List[String]) + case class BitcoinStatus(version: Int, chainHash: BlockHash, initialBlockDownload: Boolean, verificationProgress: Double, blockCount: Long, headerCount: Long, unspentAddresses: List[String]) def getBitcoinStatus(bitcoinClient: BasicBitcoinJsonRPCClient): Future[BitcoinStatus] = for { json <- bitcoinClient.invoke("getblockchaininfo").recover { case e => throw BitcoinRPCConnectionException(e) } @@ -147,7 +147,8 @@ class Setup(val datadir: File, ibd = (json \ "initialblockdownload").extract[Boolean] blocks = (json \ "blocks").extract[Long] headers = (json \ "headers").extract[Long] - chainHash <- bitcoinClient.invoke("getblockhash", 0).map(_.extract[String]).map(s => ByteVector32.fromValidHex(s)).map(_.reverse) + // NB: bitcoind confusingly returns the blockId instead of the blockHash. + chainHash <- bitcoinClient.invoke("getblockhash", 0).map(_.extract[String]).map(s => BlockId(ByteVector32.fromValidHex(s))).map(BlockHash(_)) bitcoinVersion <- bitcoinClient.invoke("getnetworkinfo").map(json => json \ "version").map(_.extract[Int]) unspentAddresses <- bitcoinClient.invoke("listunspent").recover { _ => if (wallet.isEmpty && wallets.length > 1) throw BitcoinDefaultWalletException(wallets) else throw BitcoinWalletNotLoadedException(wallet.getOrElse(""), wallets) } .collect { case JArray(values) => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/balance/BalanceActor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/balance/BalanceActor.scala index 3924d70f34..f63d77ec51 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/balance/BalanceActor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/balance/BalanceActor.scala @@ -3,7 +3,7 @@ package fr.acinq.eclair.balance import akka.actor.typed.eventstream.EventStream import akka.actor.typed.scaladsl.{ActorContext, Behaviors} import akka.actor.typed.{ActorRef, Behavior} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, TxId} import fr.acinq.eclair.NotificationsLogger import fr.acinq.eclair.NotificationsLogger.NotifyNodeOperator import fr.acinq.eclair.balance.BalanceActor._ @@ -40,11 +40,11 @@ object BalanceActor { } } - final case class UtxoInfo(utxos: Seq[Utxo], ancestorCount: Map[ByteVector32, Long]) + final case class UtxoInfo(utxos: Seq[Utxo], ancestorCount: Map[TxId, Long]) def checkUtxos(bitcoinClient: BitcoinCoreClient)(implicit ec: ExecutionContext): Future[UtxoInfo] = { - def getUnconfirmedAncestorCount(utxo: Utxo): Future[(ByteVector32, Long)] = bitcoinClient.rpcClient.invoke("getmempoolentry", utxo.txid).map(json => { + def getUnconfirmedAncestorCount(utxo: Utxo): Future[(TxId, Long)] = bitcoinClient.rpcClient.invoke("getmempoolentry", utxo.txid).map(json => { val JInt(ancestorCount) = json \ "ancestorcount" (utxo.txid, ancestorCount.toLong) }).recover { @@ -55,7 +55,7 @@ object BalanceActor { (utxo.txid, 0) } - def getUnconfirmedAncestorCountMap(utxos: Seq[Utxo]): Future[Map[ByteVector32, Long]] = Future.sequence(utxos.filter(_.confirmations == 0).map(getUnconfirmedAncestorCount)).map(_.toMap) + def getUnconfirmedAncestorCountMap(utxos: Seq[Utxo]): Future[Map[TxId, Long]] = Future.sequence(utxos.filter(_.confirmations == 0).map(getUnconfirmedAncestorCount)).map(_.toMap) for { utxos <- bitcoinClient.listUnspent() @@ -134,7 +134,7 @@ private class BalanceActor(context: ActorContext[Command], Behaviors.same case WrappedUtxoInfo(res) => res match { - case Success(UtxoInfo(utxos: Seq[Utxo], ancestorCount: Map[ByteVector32, Long])) => + case Success(UtxoInfo(utxos, ancestorCount)) => val filteredByStatus: Map[String, Seq[Utxo]] = Map( Monitoring.Tags.UtxoStatuses.Confirmed -> utxos.filter(utxo => utxo.confirmations > 0), // We cannot create chains of unconfirmed transactions with more than 25 elements, so we ignore such utxos. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/balance/CheckBalance.scala b/eclair-core/src/main/scala/fr/acinq/eclair/balance/CheckBalance.scala index 4c2f725587..2b3dd9e407 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/balance/CheckBalance.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/balance/CheckBalance.scala @@ -1,7 +1,7 @@ package fr.acinq.eclair.balance import com.softwaremill.quicklens._ -import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, Satoshi, SatoshiLong, Script} +import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, Satoshi, SatoshiLong, Script, TxId} import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient import fr.acinq.eclair.channel.Helpers.Closing import fr.acinq.eclair.channel.Helpers.Closing.{CurrentRemoteClose, LocalClose, NextRemoteClose, RemoteClose} @@ -51,11 +51,11 @@ object CheckBalance { * That's why we keep track of the id of each transaction that pays us any amount. It allows us to double check from * bitcoin core and remove any published transaction. */ - case class PossiblyPublishedMainBalance(toLocal: Map[ByteVector32, Btc] = Map.empty) { + case class PossiblyPublishedMainBalance(toLocal: Map[TxId, Btc] = Map.empty) { val total: Btc = toLocal.values.map(_.toSatoshi).sum } - case class PossiblyPublishedMainAndHtlcBalance(toLocal: Map[ByteVector32, Btc] = Map.empty, htlcs: Map[ByteVector32, Btc] = Map.empty, htlcsUnpublished: Btc = 0.sat) { + case class PossiblyPublishedMainAndHtlcBalance(toLocal: Map[TxId, Btc] = Map.empty, htlcs: Map[TxId, Btc] = Map.empty, htlcsUnpublished: Btc = 0.sat) { val totalToLocal: Btc = toLocal.values.map(_.toSatoshi).sum val totalHtlcs: Btc = htlcs.values.map(_.toSatoshi).sum val total: Btc = totalToLocal + totalHtlcs + htlcsUnpublished @@ -153,7 +153,7 @@ object CheckBalance { val finalScriptPubKey = Script.write(Script.pay2wpkh(c.params.localParams.walletStaticPaymentBasepoint.get)) Transactions.findPubKeyScriptIndex(remoteCommitPublished.commitTx, finalScriptPubKey) match { case Right(outputIndex) => Map(remoteCommitPublished.commitTx.txid -> remoteCommitPublished.commitTx.txOut(outputIndex).amount.toBtc) - case _ => Map.empty[ByteVector32, Btc] // either we don't have an output (below dust), or we have used a non-default pubkey script + case _ => Map.empty[TxId, Btc] // either we don't have an output (below dust), or we have used a non-default pubkey script } } else { remoteCommitPublished.claimMainOutputTx.toSeq.map(c => c.tx.txid -> c.tx.txOut.head.amount.toBtc).toMap @@ -258,13 +258,13 @@ object CheckBalance { */ def prunePublishedTransactions(br: OffChainBalance, bitcoinClient: BitcoinCoreClient)(implicit ec: ExecutionContext): Future[OffChainBalance] = { for { - txs: Iterable[Option[(ByteVector32, Int)]] <- Future.sequence((br.closing.localCloseBalance.toLocal.keys ++ + txs: Iterable[Option[(TxId, Int)]] <- Future.sequence((br.closing.localCloseBalance.toLocal.keys ++ br.closing.localCloseBalance.htlcs.keys ++ br.closing.remoteCloseBalance.toLocal.keys ++ br.closing.remoteCloseBalance.htlcs.keys ++ br.closing.mutualCloseBalance.toLocal.keys) .map(txid => bitcoinClient.getTxConfirmations(txid).map(_ map { confirmations => txid -> confirmations }))) - txMap: Map[ByteVector32, Int] = txs.flatten.toMap + txMap: Map[TxId, Int] = txs.flatten.toMap } yield { br .modifyAll( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/BlockchainEvents.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/BlockchainEvents.scala index 03d815948b..f65769062a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/BlockchainEvents.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/BlockchainEvents.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.blockchain -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockId, Transaction} import fr.acinq.eclair.BlockHeight import fr.acinq.eclair.blockchain.fee.FeeratesPerKw @@ -26,7 +26,7 @@ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw sealed trait BlockchainEvent -case class NewBlock(blockHash: ByteVector32) extends BlockchainEvent +case class NewBlock(blockId: BlockId) extends BlockchainEvent case class NewTransaction(tx: Transaction) extends BlockchainEvent diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/OnChainWallet.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/OnChainWallet.scala index bc2ac328b5..dc9c1a0f6f 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/OnChainWallet.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/OnChainWallet.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.blockchain import fr.acinq.bitcoin.psbt.Psbt import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{OutPoint, Satoshi, Transaction, TxId} import fr.acinq.eclair.blockchain.fee.FeeratePerKw import scodec.bits.ByteVector @@ -52,7 +52,7 @@ trait OnChainChannelFunder { * Publish a transaction on the bitcoin network. * This method must be idempotent: if the tx was already published, it must return a success. */ - def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] + def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] /** Create a fully signed channel funding transaction with the provided pubkeyScript. */ def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRate: FeeratePerKw)(implicit ec: ExecutionContext): Future[MakeFundingTxResponse] @@ -70,10 +70,10 @@ trait OnChainChannelFunder { def commit(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] /** Return the transaction if it exists, either in the blockchain or in the mempool. */ - def getTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] + def getTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Transaction] /** Get the number of confirmations of a given transaction. */ - def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] + def getTxConfirmations(txId: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] /** Rollback a transaction that we failed to commit: this probably translates to "release locks on utxos". */ def rollback(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] @@ -139,9 +139,9 @@ object OnChainWallet { /** Transaction with all available witnesses. */ val partiallySignedTx: Transaction = { - var tx = psbt.getGlobal.getTx - for (i <- 0 until psbt.getInputs.size()) { - Option(psbt.getInputs.get(i).getScriptWitness).foreach { witness => + var tx = psbt.global.tx + for (i <- 0 until psbt.inputs.size()) { + Option(psbt.inputs.get(i).getScriptWitness).foreach { witness => tx = tx.updateWitness(i, witness) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index a70885a8bb..2ec66eaf1d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -61,14 +61,14 @@ object ZmqWatcher { private case class GetBlockCountFailed(t: Throwable) extends Command private case class CheckBlockHeight(current: BlockHeight) extends Command private case class PublishBlockHeight(current: BlockHeight) extends Command - private case class ProcessNewBlock(blockHash: ByteVector32) extends Command + private case class ProcessNewBlock(blockId: BlockId) extends Command private case class ProcessNewTransaction(tx: Transaction) extends Command final case class ValidateRequest(replyTo: ActorRef[ValidateResult], ann: ChannelAnnouncement) extends Command final case class ValidateResult(c: ChannelAnnouncement, fundingTx: Either[Throwable, (Transaction, UtxoStatus)]) - final case class GetTxWithMeta(replyTo: ActorRef[GetTxWithMetaResponse], txid: ByteVector32) extends Command - final case class GetTxWithMetaResponse(txid: ByteVector32, tx_opt: Option[Transaction], lastBlockTimestamp: TimestampSecond) + final case class GetTxWithMeta(replyTo: ActorRef[GetTxWithMetaResponse], txid: TxId) extends Command + final case class GetTxWithMetaResponse(txid: TxId, tx_opt: Option[Transaction], lastBlockTimestamp: TimestampSecond) sealed trait UtxoStatus object UtxoStatus { @@ -79,7 +79,7 @@ object ZmqWatcher { /** Watch for confirmation of a given transaction. */ sealed trait WatchConfirmed[T <: WatchConfirmedTriggered] extends Watch[T] { /** TxId of the transaction to watch. */ - def txId: ByteVector32 + def txId: TxId /** Number of confirmations. */ def minDepth: Long } @@ -93,14 +93,14 @@ object ZmqWatcher { */ sealed trait WatchSpent[T <: WatchSpentTriggered] extends Watch[T] { /** TxId of the outpoint to watch. */ - def txId: ByteVector32 + def txId: TxId /** Index of the outpoint to watch. */ def outputIndex: Int /** * TxIds of potential spending transactions; most of the time we know the txs, and it allows for optimizations. * This argument can safely be ignored by watcher implementations. */ - def hints: Set[ByteVector32] + def hints: Set[TxId] } /** @@ -112,7 +112,7 @@ object ZmqWatcher { */ sealed trait WatchSpentBasic[T <: WatchSpentBasicTriggered] extends Watch[T] { /** TxId of the outpoint to watch. */ - def txId: ByteVector32 + def txId: TxId /** Index of the outpoint to watch. */ def outputIndex: Int } @@ -136,32 +136,32 @@ object ZmqWatcher { /** This event is sent when a [[WatchSpentBasic]] condition is met. */ sealed trait WatchSpentBasicTriggered extends WatchTriggered - case class WatchExternalChannelSpent(replyTo: ActorRef[WatchExternalChannelSpentTriggered], txId: ByteVector32, outputIndex: Int, shortChannelId: RealShortChannelId) extends WatchSpentBasic[WatchExternalChannelSpentTriggered] + case class WatchExternalChannelSpent(replyTo: ActorRef[WatchExternalChannelSpentTriggered], txId: TxId, outputIndex: Int, shortChannelId: RealShortChannelId) extends WatchSpentBasic[WatchExternalChannelSpentTriggered] case class WatchExternalChannelSpentTriggered(shortChannelId: RealShortChannelId) extends WatchSpentBasicTriggered - case class WatchFundingSpent(replyTo: ActorRef[WatchFundingSpentTriggered], txId: ByteVector32, outputIndex: Int, hints: Set[ByteVector32]) extends WatchSpent[WatchFundingSpentTriggered] + case class WatchFundingSpent(replyTo: ActorRef[WatchFundingSpentTriggered], txId: TxId, outputIndex: Int, hints: Set[TxId]) extends WatchSpent[WatchFundingSpentTriggered] case class WatchFundingSpentTriggered(spendingTx: Transaction) extends WatchSpentTriggered - case class WatchOutputSpent(replyTo: ActorRef[WatchOutputSpentTriggered], txId: ByteVector32, outputIndex: Int, hints: Set[ByteVector32]) extends WatchSpent[WatchOutputSpentTriggered] + case class WatchOutputSpent(replyTo: ActorRef[WatchOutputSpentTriggered], txId: TxId, outputIndex: Int, hints: Set[TxId]) extends WatchSpent[WatchOutputSpentTriggered] case class WatchOutputSpentTriggered(spendingTx: Transaction) extends WatchSpentTriggered /** Waiting for a wallet transaction to be published guarantees that bitcoind won't double-spend it in the future, unless we explicitly call abandontransaction. */ - case class WatchPublished(replyTo: ActorRef[WatchPublishedTriggered], txId: ByteVector32) extends Watch[WatchPublishedTriggered] + case class WatchPublished(replyTo: ActorRef[WatchPublishedTriggered], txId: TxId) extends Watch[WatchPublishedTriggered] case class WatchPublishedTriggered(tx: Transaction) extends WatchTriggered - case class WatchFundingConfirmed(replyTo: ActorRef[WatchFundingConfirmedTriggered], txId: ByteVector32, minDepth: Long) extends WatchConfirmed[WatchFundingConfirmedTriggered] + case class WatchFundingConfirmed(replyTo: ActorRef[WatchFundingConfirmedTriggered], txId: TxId, minDepth: Long) extends WatchConfirmed[WatchFundingConfirmedTriggered] case class WatchFundingConfirmedTriggered(blockHeight: BlockHeight, txIndex: Int, tx: Transaction) extends WatchConfirmedTriggered - case class WatchFundingDeeplyBuried(replyTo: ActorRef[WatchFundingDeeplyBuriedTriggered], txId: ByteVector32, minDepth: Long) extends WatchConfirmed[WatchFundingDeeplyBuriedTriggered] + case class WatchFundingDeeplyBuried(replyTo: ActorRef[WatchFundingDeeplyBuriedTriggered], txId: TxId, minDepth: Long) extends WatchConfirmed[WatchFundingDeeplyBuriedTriggered] case class WatchFundingDeeplyBuriedTriggered(blockHeight: BlockHeight, txIndex: Int, tx: Transaction) extends WatchConfirmedTriggered - case class WatchTxConfirmed(replyTo: ActorRef[WatchTxConfirmedTriggered], txId: ByteVector32, minDepth: Long) extends WatchConfirmed[WatchTxConfirmedTriggered] + case class WatchTxConfirmed(replyTo: ActorRef[WatchTxConfirmedTriggered], txId: TxId, minDepth: Long) extends WatchConfirmed[WatchTxConfirmedTriggered] case class WatchTxConfirmedTriggered(blockHeight: BlockHeight, txIndex: Int, tx: Transaction) extends WatchConfirmedTriggered - case class WatchParentTxConfirmed(replyTo: ActorRef[WatchParentTxConfirmedTriggered], txId: ByteVector32, minDepth: Long) extends WatchConfirmed[WatchParentTxConfirmedTriggered] + case class WatchParentTxConfirmed(replyTo: ActorRef[WatchParentTxConfirmedTriggered], txId: TxId, minDepth: Long) extends WatchConfirmed[WatchParentTxConfirmedTriggered] case class WatchParentTxConfirmedTriggered(blockHeight: BlockHeight, txIndex: Int, tx: Transaction) extends WatchConfirmedTriggered - case class WatchAlternativeCommitTxConfirmed(replyTo: ActorRef[WatchAlternativeCommitTxConfirmedTriggered], txId: ByteVector32, minDepth: Long) extends WatchConfirmed[WatchAlternativeCommitTxConfirmedTriggered] + case class WatchAlternativeCommitTxConfirmed(replyTo: ActorRef[WatchAlternativeCommitTxConfirmedTriggered], txId: TxId, minDepth: Long) extends WatchConfirmed[WatchAlternativeCommitTxConfirmedTriggered] case class WatchAlternativeCommitTxConfirmedTriggered(blockHeight: BlockHeight, txIndex: Int, tx: Transaction) extends WatchConfirmedTriggered private sealed trait AddWatchResult @@ -171,7 +171,7 @@ object ZmqWatcher { def apply(nodeParams: NodeParams, blockCount: AtomicLong, client: BitcoinCoreClient): Behavior[Command] = Behaviors.setup { context => - context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NewBlock](b => ProcessNewBlock(b.blockHash))) + context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NewBlock](b => ProcessNewBlock(b.blockId))) context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NewTransaction](t => ProcessNewTransaction(t.tx))) Behaviors.withTimers { timers => // we initialize block count @@ -184,8 +184,8 @@ object ZmqWatcher { private def utxo(w: GenericWatch): Option[OutPoint] = { w match { - case w: WatchSpent[_] => Some(OutPoint(w.txId.reverse, w.outputIndex)) - case w: WatchSpentBasic[_] => Some(OutPoint(w.txId.reverse, w.outputIndex)) + case w: WatchSpent[_] => Some(OutPoint(w.txId, w.outputIndex)) + case w: WatchSpentBasic[_] => Some(OutPoint(w.txId, w.outputIndex)) case _ => None } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala index 30c7d342d8..4c05b98036 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.blockchain.bitcoind.rpc import fr.acinq.eclair.KamonExt import fr.acinq.eclair.blockchain.Monitoring.{Metrics, Tags} -import fr.acinq.eclair.json.{ByteVector32KmpSerializer, ByteVector32Serializer} +import fr.acinq.eclair.json._ import org.json4s.JsonAST.JValue import org.json4s.jackson.{JacksonSerialization, Serialization} import org.json4s.{DefaultFormats, Formats} @@ -34,7 +34,11 @@ import scala.util.{Failure, Success, Try} class BasicBitcoinJsonRPCClient(rpcAuthMethod: BitcoinJsonRPCAuthMethod, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false, override val wallet: Option[String] = None)(implicit sb: SttpBackend[Future, _]) extends BitcoinJsonRPCClient { - implicit val formats: Formats = DefaultFormats.withBigDecimal + ByteVector32Serializer + ByteVector32KmpSerializer + implicit val formats: Formats = DefaultFormats.withBigDecimal + + ByteVector32Serializer + ByteVector32KmpSerializer + + TxIdSerializer + TxIdKmpSerializer + + BlockHashSerializer + BlockHashKmpSerializer + + BlockIdSerializer + BlockIdKmpSerializer private val scheme = if (ssl) "https" else "http" private val serviceUri = wallet match { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala index e049611ec7..376a160e72 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala @@ -64,15 +64,15 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag //------------------------- TRANSACTIONS -------------------------// - def getTransaction(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] = + def getTransaction(txid: TxId)(implicit ec: ExecutionContext): Future[Transaction] = getRawTransaction(txid).map(raw => Transaction.read(raw)) - private def getRawTransaction(txid: ByteVector32)(implicit ec: ExecutionContext): Future[String] = + private def getRawTransaction(txid: TxId)(implicit ec: ExecutionContext): Future[String] = rpcClient.invoke("getrawtransaction", txid).collect { case JString(raw) => raw } - def getTransactionMeta(txid: ByteVector32)(implicit ec: ExecutionContext): Future[GetTxWithMetaResponse] = + def getTransactionMeta(txid: TxId)(implicit ec: ExecutionContext): Future[GetTxWithMetaResponse] = for { tx_opt <- getTransaction(txid).map(Some(_)).recover { case _ => None } blockchainInfo <- rpcClient.invoke("getblockchaininfo") @@ -80,7 +80,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag } yield GetTxWithMetaResponse(txid, tx_opt, TimestampSecond(timestamp.toLong)) /** Get the number of confirmations of a given transaction. */ - def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = + def getTxConfirmations(txid: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = rpcClient.invoke("getrawtransaction", txid, 1 /* verbose output is needed to get the number of confirmations */) .map(json => Some((json \ "confirmations").extractOrElse[Int](0))) .recover { @@ -88,9 +88,9 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag } /** Get the hash of the block containing a given transaction. */ - private def getTxBlockHash(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[ByteVector32]] = + private def getTxBlockId(txid: TxId)(implicit ec: ExecutionContext): Future[Option[BlockId]] = rpcClient.invoke("getrawtransaction", txid, 1 /* verbose output is needed to get the block hash */) - .map(json => (json \ "blockhash").extractOpt[String].map(ByteVector32.fromValidHex)) + .map(json => (json \ "blockhash").extractOpt[String].map(b => BlockId(ByteVector32.fromValidHex(b)))) .recover { case t: JsonRPCError if t.error.code == -5 => None // Invalid or non-wallet transaction id (code: -5) } @@ -99,13 +99,13 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * @return a Future[height, index] where height is the height of the block where this transaction was published, and * index is the index of the transaction in that block. */ - def getTransactionShortId(txid: ByteVector32)(implicit ec: ExecutionContext): Future[(BlockHeight, Int)] = + def getTransactionShortId(txid: TxId)(implicit ec: ExecutionContext): Future[(BlockHeight, Int)] = for { - Some(blockHash) <- getTxBlockHash(txid) - json <- rpcClient.invoke("getblock", blockHash) + Some(blockId) <- getTxBlockId(txid) + json <- rpcClient.invoke("getblock", blockId) JInt(height) = json \ "height" JArray(txs) = json \ "tx" - index = txs.indexOf(JString(txid.toHex)) + index = txs.indexOf(JString(txid.value.toHex)) } yield (BlockHeight(height.toInt), index) /** @@ -115,7 +115,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * (not in the blockchain nor in the mempool) but could reappear later and be spendable at that point. If you want to * ensure that an output is not spendable anymore, you should use [[isTransactionOutputSpent]]. */ - def isTransactionOutputSpendable(txid: ByteVector32, outputIndex: Int, includeMempool: Boolean)(implicit ec: ExecutionContext): Future[Boolean] = + def isTransactionOutputSpendable(txid: TxId, outputIndex: Int, includeMempool: Boolean)(implicit ec: ExecutionContext): Future[Boolean] = for { json <- rpcClient.invoke("gettxout", txid, outputIndex, includeMempool) } yield json != JNull @@ -124,7 +124,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * Return true if this output has already been spent by a confirmed transaction. * Note that a reorg may invalidate the result of this function and make a spent output spendable again. */ - private def isTransactionOutputSpent(txid: ByteVector32, outputIndex: Int)(implicit ec: ExecutionContext): Future[Boolean] = { + private def isTransactionOutputSpent(txid: TxId, outputIndex: Int)(implicit ec: ExecutionContext): Future[Boolean] = { getTxConfirmations(txid).flatMap { case Some(confirmations) if confirmations > 0 => // There is an important limitation when using isTransactionOutputSpendable: if it returns false, it can mean a @@ -170,9 +170,9 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag } yield doubleSpent /** Search for mempool transaction spending a given output. */ - def lookForMempoolSpendingTx(txid: ByteVector32, outputIndex: Int)(implicit ec: ExecutionContext): Future[Transaction] = { + def lookForMempoolSpendingTx(txid: TxId, outputIndex: Int)(implicit ec: ExecutionContext): Future[Transaction] = { rpcClient.invoke("gettxspendingprevout", Seq(OutpointArg(txid, outputIndex))).collect { - case JArray(results) => results.flatMap(result => (result \ "spendingtxid").extractOpt[String].map(ByteVector32.fromValidHex)) + case JArray(results) => results.flatMap(result => (result \ "spendingtxid").extractOpt[String].map(TxId.fromValidHex)) }.flatMap { spendingTxIds => spendingTxIds.headOption match { case Some(spendingTxId) => getTransaction(spendingTxId) @@ -186,31 +186,28 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * It isn't useful to look at the whole blockchain history: if the transaction was confirmed long ago, an attacker * will have already claimed all possible outputs and there's nothing we can do about it. * - * @param blockhash_opt hash of a block *after* the output has been spent. If not provided, we will use the blockchain tip. + * @param blockHash_opt hash of a block *after* the output has been spent. If not provided, we will use the blockchain tip. * @param txid id of the transaction output that has been spent. * @param outputIndex index of the transaction output that has been spent. * @param limit maximum number of previous blocks to scan. * @return the transaction spending the given output. */ - def lookForSpendingTx(blockhash_opt: Option[ByteVector32], txid: ByteVector32, outputIndex: Int, limit: Int)(implicit ec: ExecutionContext): Future[Transaction] = { - lookForSpendingTx(blockhash_opt.map(KotlinUtils.scala2kmp), KotlinUtils.scala2kmp(txid), outputIndex, limit) - } - - def lookForSpendingTx(blockhash_opt: Option[fr.acinq.bitcoin.ByteVector32], txid: fr.acinq.bitcoin.ByteVector32, outputIndex: Int, limit: Int)(implicit ec: ExecutionContext): Future[Transaction] = + def lookForSpendingTx(blockHash_opt: Option[BlockHash], txid: TxId, outputIndex: Int, limit: Int)(implicit ec: ExecutionContext): Future[Transaction] = { for { - blockhash <- blockhash_opt match { - case Some(b) => Future.successful(b) - case None => rpcClient.invoke("getbestblockhash").collect { case JString(b) => ByteVector32.fromValidHex(b) } + blockId <- blockHash_opt match { + case Some(blockHash) => Future.successful(BlockId(blockHash)) + // NB: bitcoind confusingly returns the blockId instead of the blockHash. + case None => rpcClient.invoke("getbestblockhash").collect { case JString(blockId) => BlockId(ByteVector32.fromValidHex(blockId)) } } // with a verbosity of 0, getblock returns the raw serialized block - block <- rpcClient.invoke("getblock", blockhash, 0).collect { case JString(b) => Block.read(b) } - prevblockhash = block.header.hashPreviousBlock.reversed() - res <- block.tx.asScala.find(tx => tx.txIn.asScala.exists(i => i.outPoint.txid == txid && i.outPoint.index == outputIndex)) match { + block <- rpcClient.invoke("getblock", blockId, 0).collect { case JString(b) => Block.read(b) } + res <- block.tx.asScala.find(tx => tx.txIn.asScala.exists(i => i.outPoint.txid == KotlinUtils.scala2kmp(txid) && i.outPoint.index == outputIndex)) match { case Some(tx) => Future.successful(KotlinUtils.kmp2scala(tx)) - case None if limit > 0 => lookForSpendingTx(Some(prevblockhash), txid, outputIndex, limit - 1) + case None if limit > 0 => lookForSpendingTx(Some(KotlinUtils.kmp2scala(block.header.hashPreviousBlock)), txid, outputIndex, limit - 1) case None => Future.failed(new RuntimeException(s"couldn't find tx spending $txid:$outputIndex in the blockchain")) } } yield res + } def listTransactions(count: Int, skip: Int)(implicit ec: ExecutionContext): Future[List[WalletTx]] = rpcClient.invoke("listtransactions", "*", count, skip).map { case JArray(txs) => txs.map(tx => { @@ -222,14 +219,14 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag case _ => Satoshi(0) } val JInt(confirmations) = tx \ "confirmations" - // while transactions are still in the mempool, block hash will no be included - val blockHash = tx \ "blockhash" match { - case JString(blockHash) => ByteVector32.fromValidHex(blockHash) - case _ => ByteVector32.Zeroes + // while transactions are still in the mempool, blockId will not be included + val blockId_opt = tx \ "blockhash" match { + case JString(blockId) => Some(BlockId(ByteVector32.fromValidHex(blockId))) + case _ => None } val JString(txid) = tx \ "txid" val JInt(timestamp) = tx \ "time" - WalletTx(address, toSatoshi(amount), fee, blockHash, confirmations.toLong, ByteVector32.fromValidHex(txid), timestamp.toLong) + WalletTx(address, toSatoshi(amount), fee, blockId_opt, confirmations.toLong, TxId.fromValidHex(txid), timestamp.toLong) }).reverse case _ => Nil } @@ -409,9 +406,9 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag } /** Recursively fetch unconfirmed parents and return the complete unconfirmed ancestors tree. */ - def getMempoolPackage(leaves: Set[ByteVector32])(implicit ec: ExecutionContext): Future[Map[ByteVector32, MempoolTx]] = getMempoolPackage(leaves, Map.empty) + def getMempoolPackage(leaves: Set[TxId])(implicit ec: ExecutionContext): Future[Map[TxId, MempoolTx]] = getMempoolPackage(leaves, Map.empty) - private def getMempoolPackage(leaves: Set[ByteVector32], current: Map[ByteVector32, MempoolTx])(implicit ec: ExecutionContext): Future[Map[ByteVector32, MempoolTx]] = { + private def getMempoolPackage(leaves: Set[TxId], current: Map[TxId, MempoolTx])(implicit ec: ExecutionContext): Future[Map[TxId, MempoolTx]] = { Future.sequence(leaves.map(txid => getMempoolTx(txid))).flatMap(txs => { val current2 = current.concat(txs.map(tx => tx.txid -> tx)) val remainingParents = txs.flatMap(_.unconfirmedParents) -- current2.keySet @@ -468,9 +465,9 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * * @return the transaction id (txid) */ - def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] = + def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] = rpcClient.invoke("sendrawtransaction", tx.toString()).collect { - case JString(txid) => ByteVector32.fromValidHex(txid) + case JString(txid) => TxId.fromValidHex(txid) }.recoverWith { case JsonRPCError(Error(-27, _)) => // "transaction already in block chain (code: -27)" @@ -485,7 +482,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * This method can be used to replace "stuck" or evicted transactions. * It only works on transactions which are not included in a block and are not currently in the mempool. */ - def abandonTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Boolean] = { + def abandonTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Boolean] = { rpcClient.invoke("abandontransaction", txId).map(_ => true).recover(_ => false) } @@ -495,7 +492,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag case JArray(locks) => locks.map(item => { val JString(txid) = item \ "txid" val JInt(vout) = item \ "vout" - OutPoint(ByteVector32.fromValidHex(txid).reverse, vout.toInt) + OutPoint(TxId.fromValidHex(txid), vout.toInt) }).toSet } } @@ -544,9 +541,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag // and that the address and public key match onChainKeyManager_opt match { case Some(keyManager) => - // TODO: bitcoin-kmp doesn't accept 'h' for hardened indexes, we should fix this. - val keyPath1 = keyPath.replace('h', '\'') - val computed = keyManager.derivePublicKey(DeterministicWallet.KeyPath(keyPath1)) + val computed = keyManager.derivePublicKey(DeterministicWallet.KeyPath(keyPath)) if (computed != (extracted, address)) return Future.failed(new RuntimeException("cannot recompute pubkey generated by bitcoin core")) case None => () } @@ -583,7 +578,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag * @param feeratePerKw fee rate * @return the txid of the sending tx. */ - def sendToPubkeyScript(pubkeyScript: ByteVector, amount: Satoshi, feeratePerKw: FeeratePerKw)(implicit ec: ExecutionContext): Future[ByteVector32] = { + def sendToPubkeyScript(pubkeyScript: ByteVector, amount: Satoshi, feeratePerKw: FeeratePerKw)(implicit ec: ExecutionContext): Future[TxId] = { import KotlinUtils._ val theirOutput = TxOut(amount, pubkeyScript) @@ -603,10 +598,10 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag } yield txid } - def sendToPubkeyScript(pubkeyScript: Seq[ScriptElt], amount: Satoshi, feeratePerKw: FeeratePerKw)(implicit ec: ExecutionContext): Future[ByteVector32] = sendToPubkeyScript(Script.write(pubkeyScript), amount, feeratePerKw) + def sendToPubkeyScript(pubkeyScript: Seq[ScriptElt], amount: Satoshi, feeratePerKw: FeeratePerKw)(implicit ec: ExecutionContext): Future[TxId] = sendToPubkeyScript(Script.write(pubkeyScript), amount, feeratePerKw) /** Calls Bitcoin Core's sendtoaddress RPC call directly. Will fail if wallet is using an external signer. */ - def sendToAddress(address: String, amount: Satoshi, confirmationTarget: Long)(implicit ec: ExecutionContext): Future[ByteVector32] = { + def sendToAddress(address: String, amount: Satoshi, confirmationTarget: Long)(implicit ec: ExecutionContext): Future[TxId] = { rpcClient.invoke( "sendtoaddress", address, @@ -616,7 +611,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag false, // subtractfeefromamount true, // replaceable confirmationTarget).collect { - case JString(txid) => ByteVector32.fromValidHex(txid) + case JString(txid) => TxId.fromValidHex(txid) } } @@ -624,12 +619,12 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag def getMempool()(implicit ec: ExecutionContext): Future[Seq[Transaction]] = for { - txids <- rpcClient.invoke("getrawmempool").map(json => json.extract[List[String]].map(ByteVector32.fromValidHex)) + txids <- rpcClient.invoke("getrawmempool").map(json => json.extract[List[String]].map(TxId.fromValidHex)) // NB: if a transaction is evicted before we've called getTransaction, we need to ignore it instead of failing. txs <- Future.sequence(txids.map(getTransaction(_).map(Some(_)).recover { case _ => None })) } yield txs.flatten - def getMempoolTx(txid: ByteVector32)(implicit ec: ExecutionContext): Future[MempoolTx] = { + def getMempoolTx(txid: TxId)(implicit ec: ExecutionContext): Future[MempoolTx] = { rpcClient.invoke("getmempoolentry", txid).map(json => { val JInt(vsize) = json \ "vsize" val JInt(weight) = json \ "weight" @@ -639,7 +634,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag val JDecimal(ancestorFees) = json \ "fees" \ "ancestor" val JDecimal(descendantFees) = json \ "fees" \ "descendant" val JBool(replaceable) = json \ "bip125-replaceable" - val unconfirmedParents = (json \ "depends").extract[List[String]].map(ByteVector32.fromValidHex).toSet + val unconfirmedParents = (json \ "depends").extract[List[String]].map(TxId.fromValidHex).toSet // NB: bitcoind counts the transaction itself as its own ancestor and descendant, which is confusing: we fix that by decrementing these counters. MempoolTx(txid, vsize.toLong, weight.toLong, replaceable, toSatoshi(fees), ancestorCount.toInt - 1, toSatoshi(ancestorFees), descendantCount.toInt - 1, toSatoshi(descendantFees), unconfirmedParents) }) @@ -662,11 +657,11 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag def validate(c: ChannelAnnouncement)(implicit ec: ExecutionContext): Future[ValidateResult] = { val TxCoordinates(blockHeight, txIndex, outputIndex) = coordinates(c.shortChannelId) for { - blockHash <- rpcClient.invoke("getblockhash", blockHeight.toInt).map(_.extractOpt[String].map(ByteVector32.fromValidHex).getOrElse(ByteVector32.Zeroes)) - txid: ByteVector32 <- rpcClient.invoke("getblock", blockHash).map(json => Try { + blockId <- rpcClient.invoke("getblockhash", blockHeight.toInt).map(_.extractOpt[String].map(b => BlockId(ByteVector32.fromValidHex(b))).getOrElse(BlockId(ByteVector32.Zeroes))) + txid <- rpcClient.invoke("getblock", blockId).map(json => Try { val JArray(txs) = json \ "tx" - ByteVector32.fromValidHex(txs(txIndex).extract[String]) - }.getOrElse(ByteVector32.Zeroes)) + TxId.fromValidHex(txs(txIndex).extract[String]) + }.getOrElse(TxId(ByteVector32.Zeroes))) tx <- getRawTransaction(txid) unspent <- isTransactionOutputSpendable(txid, outputIndex, includeMempool = true) fundingTxStatus <- if (unspent) { @@ -690,7 +685,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val onChainKeyManag case JString(label) => Some(label) case _ => None } - Utxo(ByteVector32.fromValidHex(txid), (amount.doubleValue * 1000).millibtc, confirmations.toLong, safe, label) + Utxo(TxId.fromValidHex(txid), (amount.doubleValue * 1000).millibtc, confirmations.toLong, safe, label) }) } @@ -705,7 +700,7 @@ object BitcoinCoreClient { case class InputWeight(txid: String, vout: Long, weight: Long) object InputWeight { - def apply(outPoint: OutPoint, weight: Long): InputWeight = InputWeight(outPoint.txid.toHex, outPoint.index, weight) + def apply(outPoint: OutPoint, weight: Long): InputWeight = InputWeight(outPoint.txid.value.toHex, outPoint.index, weight) } case class FundTransactionOptions(feeRate: BigDecimal, replaceable: Boolean, lockUnspents: Boolean, changePosition: Option[Int], input_weights: Option[Seq[InputWeight]]) @@ -744,14 +739,14 @@ object BitcoinCoreClient { * @param descendantFees transactions fees for the package consisting of this transaction and its unconfirmed children (without its unconfirmed parents). * @param unconfirmedParents unconfirmed transactions used as inputs for this transaction. */ - case class MempoolTx(txid: ByteVector32, vsize: Long, weight: Long, replaceable: Boolean, fees: Satoshi, ancestorCount: Int, ancestorFees: Satoshi, descendantCount: Int, descendantFees: Satoshi, unconfirmedParents: Set[ByteVector32]) + case class MempoolTx(txid: TxId, vsize: Long, weight: Long, replaceable: Boolean, fees: Satoshi, ancestorCount: Int, ancestorFees: Satoshi, descendantCount: Int, descendantFees: Satoshi, unconfirmedParents: Set[TxId]) - case class WalletTx(address: String, amount: Satoshi, fees: Satoshi, blockHash: ByteVector32, confirmations: Long, txid: ByteVector32, timestamp: Long) + case class WalletTx(address: String, amount: Satoshi, fees: Satoshi, blockId_opt: Option[BlockId], confirmations: Long, txid: TxId, timestamp: Long) /** Outpoint used as RPC argument. */ - case class OutpointArg(txid: ByteVector32, vout: Long) + case class OutpointArg(txid: TxId, vout: Long) - case class Utxo(txid: ByteVector32, amount: MilliBtc, confirmations: Long, safe: Boolean, label_opt: Option[String]) + case class Utxo(txid: TxId, amount: MilliBtc, confirmations: Long, safe: Boolean, label_opt: Option[String]) def toSatoshi(btcAmount: BigDecimal): Satoshi = Satoshi(btcAmount.bigDecimal.scaleByPowerOfTen(8).longValue) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala index fe8384d6e9..22dc3cc35e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.blockchain.bitcoind.zmq import akka.Done import akka.actor.{Actor, ActorLogging} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockId, ByteVector32, Transaction} import fr.acinq.eclair.blockchain.{NewBlock, NewTransaction} import org.zeromq.ZMQ.Event import org.zeromq.{SocketType, ZContext, ZMQ, ZMsg} @@ -92,9 +92,9 @@ class ZMQActor(address: String, topic: String, connected: Option[Promise[Done]] case msg: ZMsg => msg.popString() match { case "hashblock" => - val blockHash = ByteVector32(ByteVector(msg.pop().getData)) - log.debug("received blockhash={}", blockHash) - context.system.eventStream.publish(NewBlock(blockHash)) + val blockId = BlockId(ByteVector32(ByteVector(msg.pop().getData))) + log.debug("received blockId={}", blockId) + context.system.eventStream.publish(NewBlock(blockId)) case "rawtx" => val tx = Transaction.read(msg.pop().getData) log.debug("received txid={}", tx.txid) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/BlockchainWatchdog.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/BlockchainWatchdog.scala index 2bf8728a85..3c6ea6510b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/BlockchainWatchdog.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/BlockchainWatchdog.scala @@ -104,10 +104,10 @@ object BlockchainWatchdog { case CheckLatestHeaders(blockHeight) => val id = UUID.randomUUID() if (headersOverDnsEnabled) { - context.spawn(HeadersOverDns(nodeParams.chainHash, blockHeight), s"${HeadersOverDns.Source}-${blockHeight}-$id") ! HeadersOverDns.CheckLatestHeaders(context.self) + context.spawn(HeadersOverDns(nodeParams.chainHash, blockHeight), s"${HeadersOverDns.Source}-$blockHeight-$id") ! HeadersOverDns.CheckLatestHeaders(context.self) } explorers.foreach { explorer => - context.spawn(ExplorerApi(nodeParams.chainHash, blockHeight, explorer), s"${explorer.name}-${blockHeight}-$id") ! ExplorerApi.CheckLatestHeaders(context.self) + context.spawn(ExplorerApi(nodeParams.chainHash, blockHeight, explorer), s"${explorer.name}-$blockHeight-$id") ! ExplorerApi.CheckLatestHeaders(context.self) } Behaviors.same case headers@LatestHeaders(blockHeight, blockHeaders, source) => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/ExplorerApi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/ExplorerApi.scala index 0e3d747721..e9971d620a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/ExplorerApi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/ExplorerApi.scala @@ -21,7 +21,7 @@ import akka.actor.typed.scaladsl.{ActorContext, Behaviors} import akka.actor.typed.{ActorRef, Behavior} import akka.pattern.after import fr.acinq.bitcoin.BlockHeader -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BlockId, ByteVector32} import fr.acinq.eclair.blockchain.watchdogs.BlockchainWatchdog.{BlockHeaderAt, LatestHeaders} import fr.acinq.eclair.blockchain.watchdogs.Monitoring.{Metrics, Tags} import fr.acinq.eclair.tor.Socks5ProxyParams @@ -56,7 +56,7 @@ object ExplorerApi { /** Explorer friendly-name. */ def name: String /** Map from chainHash to explorer API URI. */ - def baseUris: Map[ByteVector32, Uri] + def baseUris: Map[BlockHash, Uri] /** Fetch latest headers from the explorer. */ def getLatestHeaders(baseUri: Uri, currentBlockHeight: BlockHeight)(implicit context: ActorContext[Command]): Future[LatestHeaders] // @formatter:on @@ -69,7 +69,7 @@ object ExplorerApi { private case class WrappedFailure(e: Throwable) extends Command // @formatter:on - def apply(chainHash: ByteVector32, currentBlockHeight: BlockHeight, explorer: Explorer): Behavior[Command] = { + def apply(chainHash: BlockHash, currentBlockHeight: BlockHeight, explorer: Explorer): Behavior[Command] = { Behaviors.setup { context => Behaviors.receiveMessage { case CheckLatestHeaders(replyTo) => @@ -164,9 +164,9 @@ object ExplorerApi { val JString(time) = block \ "time" val JInt(bits) = block \ "bits" val JInt(nonce) = block \ "nonce" - val previousBlockHash = (block \ "prev_block").extractOpt[String].map(ByteVector32.fromValidHex(_).reverse).getOrElse(ByteVector32.Zeroes) + val previousBlockId = (block \ "prev_block").extractOpt[String].map(h => BlockId(ByteVector32.fromValidHex(h))).getOrElse(BlockId(ByteVector32.Zeroes)) val merkleRoot = (block \ "mrkl_root").extractOpt[String].map(ByteVector32.fromValidHex(_).reverse).getOrElse(ByteVector32.Zeroes) - val header = new BlockHeader(version.toLong, previousBlockHash, merkleRoot, OffsetDateTime.parse(time).toEpochSecond, bits.toLong, nonce.toLong) + val header = new BlockHeader(version.toLong, BlockHash(previousBlockId), merkleRoot, OffsetDateTime.parse(time).toEpochSecond, bits.toLong, nonce.toLong) Seq(BlockHeaderAt(BlockHeight(height.toLong), header)) }) } yield header @@ -193,9 +193,9 @@ object ExplorerApi { val JInt(time) = block \ "timestamp" val JInt(bits) = block \ "bits" val JInt(nonce) = block \ "nonce" - val previousBlockHash = (block \ "previousblockhash").extractOpt[String].map(ByteVector32.fromValidHex(_).reverse).getOrElse(ByteVector32.Zeroes) + val previousBlockId = (block \ "previousblockhash").extractOpt[String].map(h => BlockId(ByteVector32.fromValidHex(h))).getOrElse(BlockId(ByteVector32.Zeroes)) val merkleRoot = (block \ "merkle_root").extractOpt[String].map(ByteVector32.fromValidHex(_).reverse).getOrElse(ByteVector32.Zeroes) - val header = new BlockHeader(version.toLong, previousBlockHash, merkleRoot, time.toLong, bits.toLong, nonce.toLong) + val header = new BlockHeader(version.toLong, BlockHash(previousBlockId), merkleRoot, time.toLong, bits.toLong, nonce.toLong) BlockHeaderAt(BlockHeight(height.toLong), header) })) .map(headers => LatestHeaders(currentBlockHeight, headers.filter(_.blockHeight >= currentBlockHeight).toSet, name)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/HeadersOverDns.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/HeadersOverDns.scala index d65ab84670..dcfae33a19 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/HeadersOverDns.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/watchdogs/HeadersOverDns.scala @@ -22,8 +22,8 @@ import akka.actor.typed.scaladsl.adapter.TypedActorRefOps import akka.actor.typed.{ActorRef, Behavior} import akka.io.dns.{AAAARecord, DnsProtocol} import akka.io.{Dns, IO} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32} import fr.acinq.bitcoin.BlockHeader +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash} import fr.acinq.eclair.BlockHeight import fr.acinq.eclair.blockchain.watchdogs.BlockchainWatchdog.BlockHeaderAt import fr.acinq.eclair.blockchain.watchdogs.Monitoring.{Metrics, Tags} @@ -46,7 +46,7 @@ object HeadersOverDns { private case class WrappedDnsFailed(cause: Throwable) extends Command // @formatter:on - def apply(chainHash: ByteVector32, currentBlockHeight: BlockHeight): Behavior[Command] = { + def apply(chainHash: BlockHash, currentBlockHeight: BlockHeight): Behavior[Command] = { Behaviors.setup { context => val dnsAdapters = { context.messageAdapter[DnsProtocol.Resolved](WrappedDnsResolved) @@ -87,7 +87,7 @@ object HeadersOverDns { stopOrCollect(replyTo, currentBlockHeight, received1, remaining - 1) case WrappedDnsFailed(ex) => - context.log.warn("bitcoinheaders.net failed to resolve: {}", ex) + context.log.warn(s"bitcoinheaders.net failed to resolve: $ex") stopOrCollect(replyTo, currentBlockHeight, received, remaining - 1) case _ => Behaviors.unhandled diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala index 9b946c5092..18163fce05 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.channel import akka.actor.{ActorRef, PossiblyHarmful, typed} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Transaction, TxId, TxOut} import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel.LocalFundingStatus.DualFundedUnconfirmedFundingTx import fr.acinq.eclair.channel.fund.InteractiveTxBuilder._ @@ -263,8 +263,8 @@ object HtlcResult { final case class RES_ADD_SETTLED[+O <: Origin, +R <: HtlcResult](origin: O, htlc: UpdateAddHtlc, result: R) extends CommandSuccess[CMD_ADD_HTLC] /** other specific responses */ -final case class RES_BUMP_FUNDING_FEE(rbfIndex: Int, fundingTxId: ByteVector32, fee: Satoshi) extends CommandSuccess[CMD_BUMP_FUNDING_FEE] -final case class RES_SPLICE(fundingTxIndex: Long, fundingTxId: ByteVector32, capacity: Satoshi, balance: MilliSatoshi) extends CommandSuccess[CMD_SPLICE] +final case class RES_BUMP_FUNDING_FEE(rbfIndex: Int, fundingTxId: TxId, fee: Satoshi) extends CommandSuccess[CMD_BUMP_FUNDING_FEE] +final case class RES_SPLICE(fundingTxIndex: Long, fundingTxId: TxId, capacity: Satoshi, balance: MilliSatoshi) extends CommandSuccess[CMD_SPLICE] final case class RES_GET_CHANNEL_STATE(state: ChannelState) extends CommandSuccess[CMD_GET_CHANNEL_STATE] final case class RES_GET_CHANNEL_DATA[+D <: ChannelData](data: D) extends CommandSuccess[CMD_GET_CHANNEL_DATA] final case class RES_GET_CHANNEL_INFO(nodeId: PublicKey, channelId: ByteVector32, channel: ActorRef, state: ChannelState, data: ChannelData) extends CommandSuccess[CMD_GET_CHANNEL_INFO] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelExceptions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelExceptions.scala index 54407e9863..cea5739003 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelExceptions.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelExceptions.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.channel -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, Satoshi, Transaction, TxId} import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.wire.protocol import fr.acinq.eclair.wire.protocol.{AnnouncementSignatures, InteractiveTxMessage, UpdateAddHtlc} @@ -36,7 +36,7 @@ case class RemoteError(e: protocol.Error) extends ChannelError class ChannelException(val channelId: ByteVector32, message: String) extends RuntimeException(message) // @formatter:off -case class InvalidChainHash (override val channelId: ByteVector32, local: ByteVector32, remote: ByteVector32) extends ChannelException(channelId, s"invalid chainHash (local=$local remote=$remote)") +case class InvalidChainHash (override val channelId: ByteVector32, local: BlockHash, remote: BlockHash) extends ChannelException(channelId, s"invalid chainHash (local=$local remote=$remote)") case class FundingAmountTooLow (override val channelId: ByteVector32, fundingAmount: Satoshi, min: Satoshi) extends ChannelException(channelId, s"invalid funding_amount=$fundingAmount (min=$min)") case class FundingAmountTooHigh (override val channelId: ByteVector32, fundingAmount: Satoshi, max: Satoshi) extends ChannelException(channelId, s"invalid funding_amount=$fundingAmount (max=$max)") case class InvalidFundingBalances (override val channelId: ByteVector32, fundingAmount: Satoshi, localBalance: MilliSatoshi, remoteBalance: MilliSatoshi) extends ChannelException(channelId, s"invalid balances funding_amount=$fundingAmount local=$localBalance remote=$remoteBalance") @@ -56,10 +56,10 @@ case class InvalidFundingTx (override val channelId: Byte case class InvalidSerialId (override val channelId: ByteVector32, serialId: UInt64) extends ChannelException(channelId, s"invalid serial_id=${serialId.toByteVector.toHex}") case class DuplicateSerialId (override val channelId: ByteVector32, serialId: UInt64) extends ChannelException(channelId, s"duplicate serial_id=${serialId.toByteVector.toHex}") case class UnknownSerialId (override val channelId: ByteVector32, serialId: UInt64) extends ChannelException(channelId, s"unknown serial_id=${serialId.toByteVector.toHex}") -case class DuplicateInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: ByteVector32, previousTxOutput: Long) extends ChannelException(channelId, s"duplicate input $previousTxId:$previousTxOutput (serial_id=${serialId.toByteVector.toHex})") -case class InputOutOfBounds (override val channelId: ByteVector32, serialId: UInt64, previousTxId: ByteVector32, previousTxOutput: Long) extends ChannelException(channelId, s"invalid input $previousTxId:$previousTxOutput (serial_id=${serialId.toByteVector.toHex})") -case class NonReplaceableInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: ByteVector32, previousTxOutput: Long, sequence: Long) extends ChannelException(channelId, s"$previousTxId:$previousTxOutput is not replaceable (serial_id=${serialId.toByteVector.toHex}, nSequence=$sequence)") -case class NonSegwitInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: ByteVector32, previousTxOutput: Long) extends ChannelException(channelId, s"$previousTxId:$previousTxOutput is not a native segwit input (serial_id=${serialId.toByteVector.toHex})") +case class DuplicateInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: TxId, previousTxOutput: Long) extends ChannelException(channelId, s"duplicate input $previousTxId:$previousTxOutput (serial_id=${serialId.toByteVector.toHex})") +case class InputOutOfBounds (override val channelId: ByteVector32, serialId: UInt64, previousTxId: TxId, previousTxOutput: Long) extends ChannelException(channelId, s"invalid input $previousTxId:$previousTxOutput (serial_id=${serialId.toByteVector.toHex})") +case class NonReplaceableInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: TxId, previousTxOutput: Long, sequence: Long) extends ChannelException(channelId, s"$previousTxId:$previousTxOutput is not replaceable (serial_id=${serialId.toByteVector.toHex}, nSequence=$sequence)") +case class NonSegwitInput (override val channelId: ByteVector32, serialId: UInt64, previousTxId: TxId, previousTxOutput: Long) extends ChannelException(channelId, s"$previousTxId:$previousTxOutput is not a native segwit input (serial_id=${serialId.toByteVector.toHex})") case class PreviousTxMissing (override val channelId: ByteVector32, serialId: UInt64) extends ChannelException(channelId, s"previous tx missing from tx_add_input (serial_id=${serialId.toByteVector.toHex})") case class InvalidSharedInput (override val channelId: ByteVector32, serialId: UInt64) extends ChannelException(channelId, s"invalid shared tx_add_input (serial_id=${serialId.toByteVector.toHex})") case class OutputBelowDust (override val channelId: ByteVector32, serialId: UInt64, amount: Satoshi, dustLimit: Satoshi) extends ChannelException(channelId, s"invalid output amount=$amount below dust=$dustLimit (serial_id=${serialId.toByteVector.toHex})") @@ -75,7 +75,7 @@ case class DualFundingAborted (override val channelId: Byte case class UnexpectedInteractiveTxMessage (override val channelId: ByteVector32, msg: InteractiveTxMessage) extends ChannelException(channelId, s"unexpected interactive-tx message (${msg.getClass.getSimpleName})") case class UnexpectedFundingSignatures (override val channelId: ByteVector32) extends ChannelException(channelId, "unexpected funding signatures (tx_signatures)") case class InvalidFundingFeerate (override val channelId: ByteVector32, targetFeerate: FeeratePerKw, actualFeerate: FeeratePerKw) extends ChannelException(channelId, s"invalid funding feerate: target=$targetFeerate actual=$actualFeerate") -case class InvalidFundingSignature (override val channelId: ByteVector32, txId_opt: Option[ByteVector32]) extends ChannelException(channelId, s"invalid funding signature: txId=${txId_opt.map(_.toHex).getOrElse("n/a")}") +case class InvalidFundingSignature (override val channelId: ByteVector32, txId_opt: Option[TxId]) extends ChannelException(channelId, s"invalid funding signature: txId=${txId_opt.map(_.toString()).getOrElse("n/a")}") case class InvalidRbfFeerate (override val channelId: ByteVector32, proposed: FeeratePerKw, expected: FeeratePerKw) extends ChannelException(channelId, s"invalid rbf attempt: the feerate must be at least $expected, you proposed $proposed") case class InvalidSpliceRequest (override val channelId: ByteVector32) extends ChannelException(channelId, "invalid splice request") case class InvalidRbfAlreadyInProgress (override val channelId: ByteVector32) extends ChannelException(channelId, "invalid rbf attempt: the current rbf attempt must be completed or aborted first") @@ -98,17 +98,17 @@ case class InvalidFinalScript (override val channelId: Byte case class MissingUpfrontShutdownScript (override val channelId: ByteVector32) extends ChannelException(channelId, "missing upfront shutdown script") case class FundingTxTimedout (override val channelId: ByteVector32) extends ChannelException(channelId, "funding tx timed out") case class FundingTxDoubleSpent (override val channelId: ByteVector32) extends ChannelException(channelId, "funding tx double spent") -case class FundingTxSpent (override val channelId: ByteVector32, spendingTxId: ByteVector32) extends ChannelException(channelId, s"funding tx has been spent by txId=$spendingTxId") +case class FundingTxSpent (override val channelId: ByteVector32, spendingTxId: TxId) extends ChannelException(channelId, s"funding tx has been spent by txId=$spendingTxId") case class HtlcsTimedoutDownstream (override val channelId: ByteVector32, htlcs: Set[UpdateAddHtlc]) extends ChannelException(channelId, s"one or more htlcs timed out downstream: ids=${htlcs.take(10).map(_.id).mkString(",")}") // we only display the first 10 ids case class HtlcsWillTimeoutUpstream (override val channelId: ByteVector32, htlcs: Set[UpdateAddHtlc]) extends ChannelException(channelId, s"one or more htlcs that should be fulfilled are close to timing out upstream: ids=${htlcs.take(10).map(_.id).mkString}") // we only display the first 10 ids case class HtlcOverriddenByLocalCommit (override val channelId: ByteVector32, htlc: UpdateAddHtlc) extends ChannelException(channelId, s"htlc ${htlc.id} was overridden by local commit") case class FeerateTooSmall (override val channelId: ByteVector32, remoteFeeratePerKw: FeeratePerKw) extends ChannelException(channelId, s"remote fee rate is too small: remoteFeeratePerKw=${remoteFeeratePerKw.toLong}") case class FeerateTooDifferent (override val channelId: ByteVector32, localFeeratePerKw: FeeratePerKw, remoteFeeratePerKw: FeeratePerKw) extends ChannelException(channelId, s"local/remote feerates are too different: remoteFeeratePerKw=${remoteFeeratePerKw.toLong} localFeeratePerKw=${localFeeratePerKw.toLong}") case class InvalidAnnouncementSignatures (override val channelId: ByteVector32, annSigs: AnnouncementSignatures) extends ChannelException(channelId, s"invalid announcement signatures: $annSigs") -case class InvalidCommitmentSignature (override val channelId: ByteVector32, fundingTxId: ByteVector32, fundingTxIndex: Long, unsignedCommitTx: Transaction) extends ChannelException(channelId, s"invalid commitment signature: fundingTxId=$fundingTxId fundingTxIndex=$fundingTxIndex commitTxId=${unsignedCommitTx.txid} commitTx=$unsignedCommitTx") -case class InvalidHtlcSignature (override val channelId: ByteVector32, txId: ByteVector32) extends ChannelException(channelId, s"invalid htlc signature: txId=$txId") -case class InvalidCloseSignature (override val channelId: ByteVector32, txId: ByteVector32) extends ChannelException(channelId, s"invalid close signature: txId=$txId") -case class InvalidCloseAmountBelowDust (override val channelId: ByteVector32, txId: ByteVector32) extends ChannelException(channelId, s"invalid closing tx: some outputs are below dust: txId=$txId") +case class InvalidCommitmentSignature (override val channelId: ByteVector32, fundingTxId: TxId, fundingTxIndex: Long, unsignedCommitTx: Transaction) extends ChannelException(channelId, s"invalid commitment signature: fundingTxId=$fundingTxId fundingTxIndex=$fundingTxIndex commitTxId=${unsignedCommitTx.txid} commitTx=$unsignedCommitTx") +case class InvalidHtlcSignature (override val channelId: ByteVector32, txId: TxId) extends ChannelException(channelId, s"invalid htlc signature: txId=$txId") +case class InvalidCloseSignature (override val channelId: ByteVector32, txId: TxId) extends ChannelException(channelId, s"invalid close signature: txId=$txId") +case class InvalidCloseAmountBelowDust (override val channelId: ByteVector32, txId: TxId) extends ChannelException(channelId, s"invalid closing tx: some outputs are below dust: txId=$txId") case class CommitSigCountMismatch (override val channelId: ByteVector32, expected: Int, actual: Int) extends ChannelException(channelId, s"commit sig count mismatch: expected=$expected actual=$actual") case class HtlcSigCountMismatch (override val channelId: ByteVector32, expected: Int, actual: Int) extends ChannelException(channelId, s"htlc sig count mismatch: expected=$expected actual=$actual") case class ForcedLocalCommit (override val channelId: ByteVector32) extends ChannelException(channelId, s"forced local commit") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 78ae2d6625..6df8ed5fda 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -3,7 +3,7 @@ package fr.acinq.eclair.channel import akka.event.LoggingAdapter import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Script, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Script, Transaction, TxId} import fr.acinq.eclair.blockchain.fee.{FeeratePerByte, FeeratePerKw, FeeratesPerKw, OnChainFeeConf} import fr.acinq.eclair.channel.Helpers.Closing import fr.acinq.eclair.channel.Monitoring.{Metrics, Tags} @@ -225,7 +225,7 @@ case class CommitTxAndRemoteSig(commitTx: CommitTx, remoteSig: ByteVector64) case class LocalCommit(index: Long, spec: CommitmentSpec, commitTxAndRemoteSig: CommitTxAndRemoteSig, htlcTxsAndRemoteSigs: List[HtlcTxAndRemoteSig]) object LocalCommit { - def fromCommitSig(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxId: ByteVector32, + def fromCommitSig(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxId: TxId, fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo, commit: CommitSig, localCommitIndex: Long, spec: CommitmentSpec, localPerCommitmentPoint: PublicKey): Either[ChannelException, LocalCommit] = { val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec) @@ -249,7 +249,7 @@ object LocalCommit { } /** The remote commitment maps to a commitment transaction that only our peer can sign and broadcast. */ -case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: ByteVector32, remotePerCommitmentPoint: PublicKey) { +case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: TxId, remotePerCommitmentPoint: PublicKey) { def sign(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo): CommitSig = { val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, index, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, remotePerCommitmentPoint, spec) val sig = keyManager.sign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), TxOwner.Remote, params.commitmentFormat) @@ -276,7 +276,7 @@ case class Commitment(fundingTxIndex: Long, localFundingStatus: LocalFundingStatus, remoteFundingStatus: RemoteFundingStatus, localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[NextRemoteCommit]) { val commitInput: InputInfo = localCommit.commitTxAndRemoteSig.commitTx.input - val fundingTxId: ByteVector32 = commitInput.outPoint.txid + val fundingTxId: TxId = commitInput.outPoint.txid val capacity: Satoshi = commitInput.txOut.amount /** Channel reserve that applies to our funds. */ @@ -1148,7 +1148,7 @@ case class Commitments(params: ChannelParams, params.channelFeatures.hasFeature(Features.DualFunding) && commitSig.batchSize == 1 && latestRemoteSig == commitSig.signature } - def localFundingSigs(fundingTxId: ByteVector32): Option[TxSignatures] = { + def localFundingSigs(fundingTxId: TxId): Option[TxSignatures] = { all.find(_.fundingTxId == fundingTxId).flatMap(_.localFundingStatus.localSigs_opt) } @@ -1158,7 +1158,7 @@ case class Commitments(params: ChannelParams, * @param updateMethod This method is tricky: it passes the fundingTxIndex of the commitment corresponding to the * fundingTxId, because in the remote case we may update several commitments. */ - private def updateFundingStatus(fundingTxId: ByteVector32, updateMethod: Long => PartialFunction[Commitment, Commitment])(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = { + private def updateFundingStatus(fundingTxId: TxId, updateMethod: Long => PartialFunction[Commitment, Commitment])(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = { all.find(_.fundingTxId == fundingTxId) match { case Some(commitment) => val commitments1 = copy( @@ -1174,7 +1174,7 @@ case class Commitments(params: ChannelParams, } } - def updateLocalFundingStatus(fundingTxId: ByteVector32, status: LocalFundingStatus)(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = + def updateLocalFundingStatus(fundingTxId: TxId, status: LocalFundingStatus)(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = updateFundingStatus(fundingTxId, _ => { case c if c.fundingTxId == fundingTxId => log.info(s"setting localFundingStatus=${status.getClass.getSimpleName} for fundingTxId=${c.fundingTxId} fundingTxIndex=${c.fundingTxIndex}") @@ -1182,7 +1182,7 @@ case class Commitments(params: ChannelParams, case c => c }) - def updateRemoteFundingStatus(fundingTxId: ByteVector32)(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = + def updateRemoteFundingStatus(fundingTxId: TxId)(implicit log: LoggingAdapter): Either[Commitments, (Commitments, Commitment)] = updateFundingStatus(fundingTxId, fundingTxIndex => { // all funding older than this one are considered locked case c if c.fundingTxId == fundingTxId || c.fundingTxIndex < fundingTxIndex => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index 348be40c6e..52567887f8 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -352,7 +352,7 @@ object Helpers { object Funding { - def makeFundingInputInfo(fundingTxId: ByteVector32, fundingTxOutputIndex: Int, fundingSatoshis: Satoshi, fundingPubkey1: PublicKey, fundingPubkey2: PublicKey): InputInfo = { + def makeFundingInputInfo(fundingTxId: TxId, fundingTxOutputIndex: Int, fundingSatoshis: Satoshi, fundingPubkey1: PublicKey, fundingPubkey2: PublicKey): InputInfo = { val fundingScript = multiSig2of2(fundingPubkey1, fundingPubkey2) val fundingTxOut = TxOut(fundingSatoshis, pay2wsh(fundingScript)) InputInfo(OutPoint(fundingTxId, fundingTxOutputIndex), fundingTxOut, write(fundingScript)) @@ -368,7 +368,7 @@ object Helpers { localFundingAmount: Satoshi, remoteFundingAmount: Satoshi, localPushAmount: MilliSatoshi, remotePushAmount: MilliSatoshi, commitTxFeerate: FeeratePerKw, - fundingTxHash: ByteVector32, fundingTxOutputIndex: Int, + fundingTxId: TxId, fundingTxOutputIndex: Int, remoteFundingPubKey: PublicKey, remoteFirstPerCommitmentPoint: PublicKey): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx)] = { makeCommitTxs(keyManager, params, @@ -378,7 +378,7 @@ object Helpers { localHtlcs = Set.empty, commitTxFeerate, fundingTxIndex = 0, - fundingTxHash, fundingTxOutputIndex, + fundingTxId, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remotePerCommitmentPoint = remoteFirstPerCommitmentPoint, localCommitmentIndex = 0, remoteCommitmentIndex = 0).map { case (localSpec, localCommit, remoteSpec, remoteCommit, _) => (localSpec, localCommit, remoteSpec, remoteCommit) @@ -396,7 +396,7 @@ object Helpers { localHtlcs: Set[DirectedHtlc], commitTxFeerate: FeeratePerKw, fundingTxIndex: Long, - fundingTxHash: ByteVector32, fundingTxOutputIndex: Int, + fundingTxId: TxId, fundingTxOutputIndex: Int, remoteFundingPubKey: PublicKey, remotePerCommitmentPoint: PublicKey, localCommitmentIndex: Long, remoteCommitmentIndex: Long): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx, Seq[HtlcTx])] = { @@ -418,7 +418,7 @@ object Helpers { val fundingPubKey = keyManager.fundingPublicKey(localParams.fundingKeyPath, fundingTxIndex) val channelKeyPath = keyManager.keyPath(localParams, channelConfig) - val commitmentInput = makeFundingInputInfo(fundingTxHash, fundingTxOutputIndex, fundingAmount, fundingPubKey.publicKey, remoteFundingPubKey) + val commitmentInput = makeFundingInputInfo(fundingTxId, fundingTxOutputIndex, fundingAmount, fundingPubKey.publicKey, remoteFundingPubKey) val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, localCommitmentIndex) val (localCommitTx, _) = Commitment.makeLocalTxs(keyManager, channelConfig, channelFeatures, localCommitmentIndex, localParams, remoteParams, fundingTxIndex, remoteFundingPubKey, commitmentInput, localPerCommitmentPoint, localSpec) val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, channelConfig, channelFeatures, remoteCommitmentIndex, localParams, remoteParams, fundingTxIndex, remoteFundingPubKey, commitmentInput, remotePerCommitmentPoint, remoteSpec) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala index 44cb81c11b..1dfcfa3a1a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala @@ -21,7 +21,7 @@ import akka.actor.typed.scaladsl.adapter.{ClassicActorContextOps, actorRefAdapte import akka.actor.{Actor, ActorContext, ActorRef, FSM, OneForOneStrategy, PossiblyHarmful, Props, SupervisorStrategy, typed} import akka.event.Logging.MDC import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi, SatoshiLong, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi, SatoshiLong, Transaction, TxId} import fr.acinq.eclair.Logs.LogCategory import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.OnChainWallet.MakeFundingTxResponse @@ -161,7 +161,7 @@ object Channel { private[channel] sealed trait BitcoinEvent extends PossiblyHarmful private[channel] case object BITCOIN_FUNDING_PUBLISH_FAILED extends BitcoinEvent private[channel] case object BITCOIN_FUNDING_TIMEOUT extends BitcoinEvent - private[channel] case class BITCOIN_FUNDING_DOUBLE_SPENT(fundingTxIds: Set[ByteVector32]) extends BitcoinEvent + private[channel] case class BITCOIN_FUNDING_DOUBLE_SPENT(fundingTxIds: Set[TxId]) extends BitcoinEvent // @formatter:on case object TickChannelOpenTimeout @@ -1135,7 +1135,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with watchFundingConfirmed(w.tx.txid, Some(nodeParams.channelConf.minDepthBlocks), delay_opt = None) maybeEmitEventsPostSplice(d.shortIds, d.commitments, commitments1) maybeUpdateMaxHtlcAmount(d.channelUpdate.htlcMaximumMsat, commitments1) - stay() using d.copy(commitments = commitments1) storing() sending SpliceLocked(d.channelId, w.tx.hash) + stay() using d.copy(commitments = commitments1) storing() sending SpliceLocked(d.channelId, w.tx.txid) case Left(_) => stay() } @@ -1144,7 +1144,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with case Right((commitments1, commitment)) => val toSend = if (d.commitments.all.exists(c => c.fundingTxId == commitment.fundingTxId && c.localFundingStatus.isInstanceOf[LocalFundingStatus.NotLocked])) { // this commitment just moved from NotLocked to Locked - Some(SpliceLocked(d.channelId, w.tx.hash)) + Some(SpliceLocked(d.channelId, w.tx.txid)) } else { // this was a zero-conf splice and we already sent our splice_locked None @@ -1156,7 +1156,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with } case Event(msg: SpliceLocked, d: DATA_NORMAL) => - d.commitments.updateRemoteFundingStatus(msg.fundingTxid) match { + d.commitments.updateRemoteFundingStatus(msg.fundingTxId) match { case Right((commitments1, _)) => maybeEmitEventsPostSplice(d.shortIds, d.commitments, commitments1) maybeUpdateMaxHtlcAmount(d.channelUpdate.htlcMaximumMsat, commitments1) @@ -1808,7 +1808,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with activeConnection = r val channelKeyPath = keyManager.keyPath(d.channelParams.localParams, d.channelParams.channelConfig) val myFirstPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, 0) - val nextFundingTlv: Set[ChannelReestablishTlv] = Set(ChannelReestablishTlv.NextFundingTlv(d.signingSession.fundingTx.txId.reverse)) + val nextFundingTlv: Set[ChannelReestablishTlv] = Set(ChannelReestablishTlv.NextFundingTlv(d.signingSession.fundingTx.txId)) val channelReestablish = ChannelReestablish( channelId = d.channelId, nextLocalCommitmentNumber = 1, @@ -1828,16 +1828,16 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with val myCurrentPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, d.commitments.localCommitIndex) val rbfTlv: Set[ChannelReestablishTlv] = d match { case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.rbfStatus match { - case RbfStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId.reverse)) + case RbfStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId)) case _ => d.latestFundingTx.sharedTx match { - case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingTlv(d.latestFundingTx.sharedTx.txId.reverse)) + case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingTlv(d.latestFundingTx.sharedTx.txId)) case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty } } case d: DATA_NORMAL => d.spliceStatus match { - case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId.reverse)) + case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId)) case _ => d.commitments.latest.localFundingStatus match { - case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _) => Set(ChannelReestablishTlv.NextFundingTlv(fundingTx.txId.reverse)) + case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _) => Set(ChannelReestablishTlv.NextFundingTlv(fundingTx.txId)) case _ => Set.empty } } @@ -1991,7 +1991,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with .filter(c => c.fundingTxIndex > 0) // only consider splice txs .collectFirst { case c if c.localFundingStatus.isInstanceOf[LocalFundingStatus.Locked] => log.debug("re-sending splice_locked for fundingTxId={}", c.fundingTxId) - SpliceLocked(d.channelId, c.fundingTxId.reverse) + SpliceLocked(d.channelId, c.fundingTxId) } sendQueue = sendQueue ++ spliceLocked diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala index f1b085e89e..e9990229ef 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel.fsm import akka.actor.Status import akka.actor.typed.scaladsl.adapter.actorRefAdapter import akka.pattern.pipe -import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Script} +import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Script, TxHash} import fr.acinq.eclair.blockchain.OnChainWallet.MakeFundingTxResponse import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ import fr.acinq.eclair.channel.Helpers.Funding @@ -212,7 +212,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { case Event(MakeFundingTxResponse(fundingTx, fundingTxOutputIndex, fundingTxFee), d@DATA_WAIT_FOR_FUNDING_INTERNAL(params, fundingAmount, pushMsat, commitTxFeerate, remoteFundingPubKey, remoteFirstPerCommitmentPoint, replyTo)) => val temporaryChannelId = params.channelId // let's create the first commitment tx that spends the yet uncommitted funding tx - Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = fundingAmount, remoteFundingAmount = 0 sat, localPushAmount = pushMsat, remotePushAmount = 0 msat, commitTxFeerate, fundingTx.hash, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match { + Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = fundingAmount, remoteFundingAmount = 0 sat, localPushAmount = pushMsat, remotePushAmount = 0 msat, commitTxFeerate, fundingTx.txid, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match { case Left(ex) => handleLocalError(ex, d, None) case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) => require(fundingTx.txOut(fundingTxOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, s"pubkey script mismatch!") @@ -220,11 +220,11 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { // signature of their initial commitment tx that pays remote pushMsat val fundingCreated = FundingCreated( temporaryChannelId = temporaryChannelId, - fundingTxHash = fundingTx.hash, + fundingTxId = fundingTx.txid, fundingOutputIndex = fundingTxOutputIndex, signature = localSigOfRemoteTx ) - val channelId = toLongId(fundingTx.hash, fundingTxOutputIndex) + val channelId = toLongId(fundingTx.txid, fundingTxOutputIndex) val params1 = params.copy(channelId = channelId) peer ! ChannelIdAssigned(self, remoteNodeId, temporaryChannelId, channelId) // we notify the peer asap so it knows how to route messages txPublisher ! SetChannelId(remoteNodeId, channelId) @@ -256,10 +256,10 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { }) when(WAIT_FOR_FUNDING_CREATED)(handleExceptions { - case Event(FundingCreated(_, fundingTxHash, fundingTxOutputIndex, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_CREATED(params, fundingAmount, pushMsat, commitTxFeerate, remoteFundingPubKey, remoteFirstPerCommitmentPoint)) => + case Event(FundingCreated(_, fundingTxId, fundingTxOutputIndex, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_CREATED(params, fundingAmount, pushMsat, commitTxFeerate, remoteFundingPubKey, remoteFirstPerCommitmentPoint)) => val temporaryChannelId = params.channelId // they fund the channel with their funding tx, so the money is theirs (but we are paid pushMsat) - Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = 0 sat, remoteFundingAmount = fundingAmount, localPushAmount = 0 msat, remotePushAmount = pushMsat, commitTxFeerate, fundingTxHash, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match { + Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = 0 sat, remoteFundingAmount = fundingAmount, localPushAmount = 0 msat, remotePushAmount = pushMsat, commitTxFeerate, fundingTxId, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match { case Left(ex) => handleLocalError(ex, d, None) case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) => // check remote signature validity @@ -267,10 +267,10 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { val localSigOfLocalTx = keyManager.sign(localCommitTx, fundingPubKey, TxOwner.Local, params.commitmentFormat) val signedLocalCommitTx = Transactions.addSigs(localCommitTx, fundingPubKey.publicKey, remoteFundingPubKey, localSigOfLocalTx, remoteSig) Transactions.checkSpendable(signedLocalCommitTx) match { - case Failure(_) => handleLocalError(InvalidCommitmentSignature(temporaryChannelId, fundingTxHash.reverse, fundingTxIndex = 0, localCommitTx.tx), d, None) + case Failure(_) => handleLocalError(InvalidCommitmentSignature(temporaryChannelId, fundingTxId, fundingTxIndex = 0, localCommitTx.tx), d, None) case Success(_) => val localSigOfRemoteTx = keyManager.sign(remoteCommitTx, fundingPubKey, TxOwner.Remote, params.commitmentFormat) - val channelId = toLongId(fundingTxHash, fundingTxOutputIndex) + val channelId = toLongId(fundingTxId, fundingTxOutputIndex) val fundingSigned = FundingSigned( channelId = channelId, signature = localSigOfRemoteTx diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala index 612afbfced..f846e44a06 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala @@ -19,14 +19,13 @@ package fr.acinq.eclair.channel.fsm import akka.actor.typed.scaladsl.adapter.{TypedActorRefOps, actorRefAdapter} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.ScriptFlags -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction, TxId} import fr.acinq.eclair.ShortChannelId import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ import fr.acinq.eclair.channel.Helpers.getRelayFees import fr.acinq.eclair.channel.LocalFundingStatus.{ConfirmedFundingTx, DualFundedUnconfirmedFundingTx, SingleFundedUnconfirmedFundingTx} import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel.{ANNOUNCEMENTS_MINCONF, BroadcastChannelUpdate, PeriodicRefresh, REFRESH_CHANNEL_UPDATE_INTERVAL} -import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire.protocol.{AnnouncementSignatures, ChannelReady, ChannelReadyTlv, TlvStream} import scala.concurrent.duration.{DurationInt, FiniteDuration} @@ -43,7 +42,7 @@ trait CommonFundingHandlers extends CommonHandlers { /** * @param delay_opt optional delay to reduce herd effect at startup. */ - def watchFundingSpent(commitment: Commitment, additionalKnownSpendingTxs: Set[ByteVector32], delay_opt: Option[FiniteDuration]): Unit = { + def watchFundingSpent(commitment: Commitment, additionalKnownSpendingTxs: Set[TxId], delay_opt: Option[FiniteDuration]): Unit = { val knownSpendingTxs = Set(commitment.localCommit.commitTxAndRemoteSig.commitTx.tx.txid, commitment.remoteCommit.txid) ++ commitment.nextRemoteCommit_opt.map(_.commit.txid).toSet ++ additionalKnownSpendingTxs val watch = WatchFundingSpent(self, commitment.commitInput.outPoint.txid, commitment.commitInput.outPoint.index.toInt, knownSpendingTxs) delay_opt match { @@ -55,7 +54,7 @@ trait CommonFundingHandlers extends CommonHandlers { /** * @param delay_opt optional delay to reduce herd effect at startup. */ - def watchFundingConfirmed(fundingTxId: ByteVector32, minDepth_opt: Option[Long], delay_opt: Option[FiniteDuration]): Unit = { + def watchFundingConfirmed(fundingTxId: TxId, minDepth_opt: Option[Long], delay_opt: Option[FiniteDuration]): Unit = { val watch = minDepth_opt match { case Some(fundingMinDepth) => WatchFundingConfirmed(self, fundingTxId, fundingMinDepth) // When using 0-conf, we make sure that the transaction was successfully published, otherwise there is a risk diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala index 98c277bf6e..a974563976 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair.channel.fsm import fr.acinq.bitcoin.scalacompat.{Transaction, TxIn} +import fr.acinq.eclair.NotificationsLogger import fr.acinq.eclair.NotificationsLogger.NotifyNodeOperator import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.channel.Helpers.Closing @@ -26,7 +27,6 @@ import fr.acinq.eclair.channel.fsm.Channel.BITCOIN_FUNDING_DOUBLE_SPENT import fr.acinq.eclair.channel.fund.InteractiveTxBuilder._ import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningSession} import fr.acinq.eclair.wire.protocol.{ChannelReady, Error} -import fr.acinq.eclair.{Features, NotificationsLogger} import scala.concurrent.Future import scala.util.{Failure, Success} diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala index f26c79051a..be551c75a7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala @@ -22,7 +22,7 @@ import akka.event.LoggingAdapter import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.psbt.Psbt import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, LexicographicalOrdering, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, LexicographicalOrdering, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut} import fr.acinq.eclair.blockchain.OnChainChannelFunder import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.Helpers.Closing.MutualClose @@ -308,13 +308,13 @@ object InteractiveTxBuilder { // @formatter:off sealed trait SignedSharedTransaction { - def txId: ByteVector32 + def txId: TxId def tx: SharedTransaction def localSigs: TxSignatures def signedTx_opt: Option[Transaction] } case class PartiallySignedSharedTransaction(tx: SharedTransaction, localSigs: TxSignatures) extends SignedSharedTransaction { - override val txId: ByteVector32 = tx.buildUnsignedTx().txid + override val txId: TxId = tx.buildUnsignedTx().txid override val signedTx_opt: Option[Transaction] = None } case class FullySignedSharedTransaction(tx: SharedTransaction, localSigs: TxSignatures, remoteSigs: TxSignatures, sharedSigs_opt: Option[ScriptWitness]) extends SignedSharedTransaction { @@ -330,7 +330,7 @@ object InteractiveTxBuilder { val outputs = (Seq(sharedTxOut) ++ localTxOut ++ remoteTxOut).sortBy(_._1).map(_._2) Transaction(2, inputs, outputs, lockTime) } - override val txId: ByteVector32 = signedTx.txid + override val txId: TxId = signedTx.txid override val signedTx_opt: Option[Transaction] = Some(signedTx) val feerate: FeeratePerKw = Transactions.fee2rate(tx.fees, signedTx.weight()) } @@ -746,7 +746,7 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon localHtlcs = purpose.localHtlcs, purpose.commitTxFeerate, fundingTxIndex = purpose.fundingTxIndex, - fundingTx.hash, fundingOutputIndex, + fundingTx.txid, fundingOutputIndex, remotePerCommitmentPoint = purpose.remotePerCommitmentPoint, remoteFundingPubKey = fundingParams.remoteFundingPubKey, localCommitmentIndex = purpose.localCommitIndex, remoteCommitmentIndex = purpose.remoteCommitIndex) match { case Left(cause) => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitor.scala index def4647af3..4346645507 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitor.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel.publish import akka.actor.typed.eventstream.EventStream import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler} import akka.actor.typed.{ActorRef, Behavior} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, Transaction, TxId} import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient import fr.acinq.eclair.channel.publish.TxPublisher.{TxPublishContext, TxRejectedReason} @@ -59,14 +59,14 @@ object MempoolTxMonitor { sealed trait TxResult sealed trait IntermediateTxResult extends TxResult /** The transaction is still unconfirmed and available in the mempool. */ - case class TxInMempool(txid: ByteVector32, blockHeight: BlockHeight, parentConfirmed: Boolean) extends IntermediateTxResult + case class TxInMempool(txid: TxId, blockHeight: BlockHeight, parentConfirmed: Boolean) extends IntermediateTxResult /** The transaction is confirmed, but hasn't reached min depth yet, we should wait for more confirmations. */ - case class TxRecentlyConfirmed(txid: ByteVector32, confirmations: Int) extends IntermediateTxResult + case class TxRecentlyConfirmed(txid: TxId, confirmations: Int) extends IntermediateTxResult sealed trait FinalTxResult extends TxResult /** The transaction is confirmed and has reached min depth. */ case class TxDeeplyBuried(tx: Transaction) extends FinalTxResult /** The transaction has been evicted from the mempool. */ - case class TxRejected(txid: ByteVector32, reason: TxPublisher.TxRejectedReason) extends FinalTxResult + case class TxRejected(txid: TxId, reason: TxPublisher.TxRejectedReason) extends FinalTxResult // @formatter:on def apply(nodeParams: NodeParams, bitcoinClient: BitcoinCoreClient, txPublishContext: TxPublishContext): Behavior[Command] = { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxPublisher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxPublisher.scala index 178afe1d8b..6903519824 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxPublisher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxPublisher.scala @@ -20,7 +20,7 @@ import akka.actor.typed.eventstream.EventStream import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler} import akka.actor.typed.{ActorRef, Behavior} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, Transaction, TxId} import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient @@ -84,9 +84,9 @@ object TxPublisher { * @param fee the fee that we're actually paying: it must be set to the mining fee, unless our peer is paying it (in * which case it must be set to zero here). */ - case class PublishFinalTx(tx: Transaction, input: OutPoint, desc: String, fee: Satoshi, parentTx_opt: Option[ByteVector32]) extends PublishTx + case class PublishFinalTx(tx: Transaction, input: OutPoint, desc: String, fee: Satoshi, parentTx_opt: Option[TxId]) extends PublishTx object PublishFinalTx { - def apply(txInfo: TransactionWithInputInfo, fee: Satoshi, parentTx_opt: Option[ByteVector32]): PublishFinalTx = PublishFinalTx(txInfo.tx, txInfo.input.outPoint, txInfo.desc, fee, parentTx_opt) + def apply(txInfo: TransactionWithInputInfo, fee: Satoshi, parentTx_opt: Option[TxId]): PublishFinalTx = PublishFinalTx(txInfo.tx, txInfo.input.outPoint, txInfo.desc, fee, parentTx_opt) } /** Publish an unsigned transaction that can be RBF-ed. */ case class PublishReplaceableTx(txInfo: ReplaceableTransactionWithInputInfo, commitment: FullCommitment) extends PublishTx { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxTimeLocksMonitor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxTimeLocksMonitor.scala index d8d5db1d3f..96976260b9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxTimeLocksMonitor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/TxTimeLocksMonitor.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel.publish import akka.actor.typed.eventstream.EventStream import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler} import akka.actor.typed.{ActorRef, Behavior} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} +import fr.acinq.bitcoin.scalacompat.{Transaction, TxId} import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{WatchParentTxConfirmed, WatchParentTxConfirmedTriggered} @@ -47,7 +47,7 @@ object TxTimeLocksMonitor { case class CheckTx(replyTo: ActorRef[TimeLocksOk], tx: Transaction, desc: String) extends Command final case class WrappedCurrentBlockHeight(currentBlockHeight: BlockHeight) extends Command private case object CheckRelativeTimeLock extends Command - private case class ParentTxConfirmed(parentTxId: ByteVector32) extends Command + private case class ParentTxConfirmed(parentTxId: TxId) extends Command // @formatter:on def apply(nodeParams: NodeParams, watcher: ActorRef[ZmqWatcher.Command], txPublishContext: TxPublishContext): Behavior[Command] = { @@ -112,7 +112,7 @@ private class TxTimeLocksMonitor(nodeParams: NodeParams, } } - def waitForParentsToConfirm(parentTxIds: Set[ByteVector32]): Behavior[Command] = { + def waitForParentsToConfirm(parentTxIds: Set[TxId]): Behavior[Command] = { Behaviors.receiveMessagePartial { case ParentTxConfirmed(parentTxId) => log.debug("parent tx of {} has been confirmed (parent txid={})", cmd.desc, parentTxId) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/WeakEntropyPool.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/WeakEntropyPool.scala index 9cadda404b..7f588cf692 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/WeakEntropyPool.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/WeakEntropyPool.scala @@ -20,7 +20,7 @@ import akka.actor.typed.Behavior import akka.actor.typed.eventstream.EventStream import akka.actor.typed.scaladsl.Behaviors import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto} +import fr.acinq.bitcoin.scalacompat.{BlockId, ByteVector32, ByteVector64, Crypto} import fr.acinq.eclair.TimestampMilli import fr.acinq.eclair.blockchain.NewBlock import fr.acinq.eclair.channel.ChannelSignatureReceived @@ -47,7 +47,7 @@ object WeakEntropyPool { // @formatter:off sealed trait Command private case object FlushEntropy extends Command - private case class WrappedNewBlock(blockHash: ByteVector32) extends Command + private case class WrappedNewBlock(blockId: BlockId) extends Command private case class WrappedPaymentRelayed(paymentHash: ByteVector32, relayedAt: TimestampMilli) extends Command private case class WrappedPeerConnected(nodeId: PublicKey) extends Command private case class WrappedChannelSignature(wtxid: ByteVector32) extends Command @@ -56,7 +56,7 @@ object WeakEntropyPool { def apply(collector: EntropyCollector): Behavior[Command] = { Behaviors.setup { context => - context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NewBlock](e => WrappedNewBlock(e.blockHash))) + context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NewBlock](e => WrappedNewBlock(e.blockId))) context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[ChannelPaymentRelayed](e => WrappedPaymentRelayed(e.paymentHash, e.timestamp))) context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[PeerConnected](e => WrappedPeerConnected(e.nodeId))) context.system.eventStream ! EventStream.Subscribe(context.messageAdapter[NodeUpdated](e => WrappedNodeUpdated(e.ann.signature))) @@ -79,7 +79,7 @@ object WeakEntropyPool { Behaviors.same } - case WrappedNewBlock(blockHash) => collecting(collector, collect(entropy_opt, blockHash ++ ByteVector.fromLong(System.currentTimeMillis()))) + case WrappedNewBlock(blockHash) => collecting(collector, collect(entropy_opt, blockHash.value ++ ByteVector.fromLong(System.currentTimeMillis()))) case WrappedPaymentRelayed(paymentHash, relayedAt) => collecting(collector, collect(entropy_opt, paymentHash ++ ByteVector.fromLong(relayedAt.toLong))) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalChannelKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalChannelKeyManager.scala index a0140c245d..ab04e54b48 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalChannelKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalChannelKeyManager.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.crypto.keymanager import com.google.common.cache.{CacheBuilder, CacheLoader, LoadingCache} import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scalacompat.DeterministicWallet._ -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, DeterministicWallet} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto, DeterministicWallet} import fr.acinq.eclair.crypto.Generators import fr.acinq.eclair.crypto.Monitoring.{Metrics, Tags} import fr.acinq.eclair.router.Announcements @@ -31,7 +31,7 @@ import kamon.tag.TagSet import scodec.bits.ByteVector object LocalChannelKeyManager { - def keyBasePath(chainHash: ByteVector32): List[Long] = (chainHash: @unchecked) match { + def keyBasePath(chainHash: BlockHash): List[Long] = (chainHash: @unchecked) match { case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash | Block.SignetGenesisBlock.hash => DeterministicWallet.hardened(46) :: DeterministicWallet.hardened(1) :: Nil case Block.LivenetGenesisBlock.hash => DeterministicWallet.hardened(47) :: DeterministicWallet.hardened(1) :: Nil } @@ -56,7 +56,7 @@ object LocalChannelKeyManager { * * @param seed seed from which the channel keys will be derived */ -class LocalChannelKeyManager(seed: ByteVector, chainHash: ByteVector32) extends ChannelKeyManager with Logging { +class LocalChannelKeyManager(seed: ByteVector, chainHash: BlockHash) extends ChannelKeyManager with Logging { private val master = DeterministicWallet.generate(seed) private val privateKeys: LoadingCache[KeyPath, ExtendedPrivateKey] = CacheBuilder.newBuilder() diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalNodeKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalNodeKeyManager.scala index 484554deff..a0cfc018ca 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalNodeKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalNodeKeyManager.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.crypto.keymanager import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scalacompat.DeterministicWallet.ExtendedPrivateKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, DeterministicWallet} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto, DeterministicWallet} import fr.acinq.eclair.router.Announcements import grizzled.slf4j.Logging import scodec.bits.ByteVector @@ -27,7 +27,7 @@ object LocalNodeKeyManager { // WARNING: if you change this path, you will change your node id even if the seed remains the same!!! // Note that the node path and the above channel path are on different branches so even if the // node key is compromised there is no way to retrieve the wallet keys - def keyBasePath(chainHash: ByteVector32): List[Long] = (chainHash: @unchecked) match { + def keyBasePath(chainHash: BlockHash): List[Long] = (chainHash: @unchecked) match { case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash | Block.SignetGenesisBlock.hash => DeterministicWallet.hardened(46) :: DeterministicWallet.hardened(0) :: Nil case Block.LivenetGenesisBlock.hash => DeterministicWallet.hardened(47) :: DeterministicWallet.hardened(0) :: Nil } @@ -39,7 +39,7 @@ object LocalNodeKeyManager { * * @param seed seed from which the node key will be derived */ -class LocalNodeKeyManager(seed: ByteVector, chainHash: ByteVector32) extends NodeKeyManager with Logging { +class LocalNodeKeyManager(seed: ByteVector, chainHash: BlockHash) extends NodeKeyManager with Logging { private val master = DeterministicWallet.generate(seed) override val nodeKey: ExtendedPrivateKey = DeterministicWallet.derivePrivateKey(master, LocalNodeKeyManager.keyBasePath(chainHash)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManager.scala index af21bfd9cf..0aa38d8194 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManager.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.crypto.keymanager import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.psbt.{Psbt, UpdateFailure} import fr.acinq.bitcoin.scalacompat.DeterministicWallet._ -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, DeterministicWallet, MnemonicCode, Satoshi, Script, computeBIP84Address} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, Crypto, DeterministicWallet, MnemonicCode, Satoshi, Script, computeBIP84Address} import fr.acinq.eclair.TimestampSecond import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient.{Descriptor, Descriptors} import grizzled.slf4j.Logging @@ -38,7 +38,7 @@ object LocalOnChainKeyManager extends Logging { * @param chainHash chain we're on * @return a LocalOnChainKeyManager instance if a configuration file exists */ - def load(datadir: File, chainHash: ByteVector32): Option[LocalOnChainKeyManager] = { + def load(datadir: File, chainHash: BlockHash): Option[LocalOnChainKeyManager] = { // we use a specific file instead of adding values to eclair's configuration file because it is available everywhere // in the code through the actor system's settings and we'd like to restrict access to the on-chain wallet seed val file = new File(datadir, "eclair-signer.conf") @@ -63,7 +63,7 @@ object LocalOnChainKeyManager extends Logging { * Eclair is in charge of signing transactions. * This is an advanced feature particularly suited when Eclair runs in a secure runtime. */ -class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, val walletTimestamp: TimestampSecond, chainHash: ByteVector32) extends OnChainKeyManager with Logging { +class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, val walletTimestamp: TimestampSecond, chainHash: BlockHash) extends OnChainKeyManager with Logging { // Master key derived from our seed. We use it to generate a BIP84 wallet that can be used: // - to generate a watch-only wallet with any BIP84-compatible bitcoin wallet @@ -72,10 +72,10 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, private val master = DeterministicWallet.generate(seed) private val fingerprint = DeterministicWallet.fingerprint(master) & 0xFFFFFFFFL private val fingerPrintHex = String.format("%8s", fingerprint.toHexString).replace(' ', '0') - // Root BIP32 on-chain path: we use BIP84 (p2wpkh) paths: m/84'/{0'/1'} + // Root BIP32 on-chain path: we use BIP84 (p2wpkh) paths: m/84h/{0h/1h} private val rootPath = chainHash match { - case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash | Block.SignetGenesisBlock.hash => "84'/1'" - case Block.LivenetGenesisBlock.hash => "84'/0'" + case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash | Block.SignetGenesisBlock.hash => "84h/1h" + case Block.LivenetGenesisBlock.hash => "84h/0h" case _ => throw new IllegalArgumentException(s"invalid chain hash $chainHash") } private val rootKey = DeterministicWallet.derivePrivateKey(master, KeyPath(rootPath)) @@ -86,7 +86,7 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, case Block.LivenetGenesisBlock.hash => zpub case _ => throw new IllegalArgumentException(s"invalid chain hash $chainHash") } - // master pubkey for account 0 is m/84'/{0'/1'}/0' + // master pubkey for account 0 is m/84h/{0h/1h}/0h val accountPub = DeterministicWallet.publicKey(DeterministicWallet.derivePrivateKey(rootKey, hardened(account))) DeterministicWallet.encode(accountPub, prefix) } @@ -98,16 +98,15 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, } override def descriptors(account: Long): Descriptors = { - // TODO: we should use 'h' everywhere once bitcoin-kmp supports it. - val keyPath = s"$rootPath/$account'".replace('\'', 'h') + val keyPath = s"$rootPath/${account}h" val prefix = chainHash match { case Block.LivenetGenesisBlock.hash => xpub case _ => tpub } val accountPub = DeterministicWallet.publicKey(DeterministicWallet.derivePrivateKey(rootKey, hardened(account))) // descriptors for account 0 are: - // 84'/{0'/1'}/0'/0/* for main addresses - // 84'/{0'/1'}/0'/1/* for change addresses + // 84h/{0h/1h}/0h/0/* for main addresses + // 84h/{0h/1h}/0h/1/* for change addresses val receiveDesc = s"wpkh([$fingerPrintHex/$keyPath]${encode(accountPub, prefix)}/0/*)" val changeDesc = s"wpkh([$fingerPrintHex/$keyPath]${encode(accountPub, prefix)}/1/*)" Descriptors(wallet_name = walletName, descriptors = List( @@ -120,7 +119,7 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, for { spent <- spentAmount(psbt, ourInputs) change <- changeAmount(psbt, ourOutputs) - _ = logger.debug(s"signing txid=${psbt.getGlobal.getTx.txid} fees=${psbt.computeFees()} spent=$spent change=$change") + _ = logger.debug(s"signing txid=${psbt.global.tx.txid} fees=${psbt.computeFees()} spent=$spent change=$change") _ <- Try { ourOutputs.foreach(i => require(isOurOutput(psbt, i), s"could not verify output $i: bitcoin core may be malicious")) } @@ -142,22 +141,22 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, private def changeAmount(psbt: Psbt, ourOutputs: Seq[Int]): Try[Satoshi] = Try { ourOutputs.map(i => { - require(psbt.getGlobal.getTx.txOut.size() > i, s"output $i is missing from psbt: bitcoin core may be malicious") - fr.acinq.bitcoin.scalacompat.KotlinUtils.kmp2scala(psbt.getGlobal.getTx.txOut.get(i).amount) + require(psbt.global.tx.txOut.size() > i, s"output $i is missing from psbt: bitcoin core may be malicious") + fr.acinq.bitcoin.scalacompat.KotlinUtils.kmp2scala(psbt.global.tx.txOut.get(i).amount) }).sum } /** Check that an output belongs to us (i.e. we can recompute its public key from its bip32 path). */ private def isOurOutput(psbt: Psbt, outputIndex: Int): Boolean = { import fr.acinq.bitcoin.scalacompat.KotlinUtils._ - if (psbt.getOutputs.size() <= outputIndex || psbt.getGlobal.getTx.txOut.size() <= outputIndex) { + if (psbt.outputs.size() <= outputIndex || psbt.global.tx.txOut.size() <= outputIndex) { return false } - val output = psbt.getOutputs.get(outputIndex) - val txOut = psbt.getGlobal.getTx.txOut.get(outputIndex) + val output = psbt.outputs.get(outputIndex) + val txOut = psbt.global.tx.txOut.get(outputIndex) output.getDerivationPaths.asScala.headOption match { case Some((pub, keypath)) => - val (expectedPubKey, _) = derivePublicKey(KeyPath(keypath.getKeyPath.path.asScala.toSeq.map(_.longValue()))) + val (expectedPubKey, _) = derivePublicKey(KeyPath(keypath.keyPath.path.asScala.toSeq.map(_.longValue()))) val expectedScript = Script.write(Script.pay2wpkh(expectedPubKey)) if (expectedPubKey != kmp2scala(pub)) { logger.warn(s"public key mismatch (expected=$expectedPubKey, actual=$pub): bitcoin core may be malicious") @@ -187,8 +186,8 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, // We check that these fields are consistent and match the outpoint that is spent in the PSBT. // This prevents attacks where Bitcoin Core would lie about the amount being spent and make us pay very high fees. require(input.getNonWitnessUtxo != null, "non-witness utxo is missing: bitcoin core may be malicious") - require(input.getNonWitnessUtxo.txid == psbt.getGlobal.getTx.txIn.get(pos).outPoint.txid, "utxo txid mismatch: bitcoin core may be malicious") - require(input.getNonWitnessUtxo.txOut.get(psbt.getGlobal.getTx.txIn.get(pos).outPoint.index.toInt) == input.getWitnessUtxo, "utxo mismatch: bitcoin core may be malicious") + require(input.getNonWitnessUtxo.txid == psbt.global.tx.txIn.get(pos).outPoint.txid, "utxo txid mismatch: bitcoin core may be malicious") + require(input.getNonWitnessUtxo.txOut.get(psbt.global.tx.txIn.get(pos).outPoint.index.toInt) == input.getWitnessUtxo, "utxo mismatch: bitcoin core may be malicious") // We must use SIGHASH_ALL, otherwise we would be vulnerable to "signature reuse" attacks. // When unspecified, the sighash used will be SIGHASH_ALL. @@ -197,13 +196,13 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector, // Check that we're signing a p2wpkh input and that the keypath is provided and correct. require(input.getDerivationPaths.size() == 1, "bip32 derivation path is missing: bitcoin core may be malicious") val (pub, keypath) = input.getDerivationPaths.asScala.toSeq.head - val priv = fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey(master.priv, keypath.getKeyPath).getPrivateKey + val priv = fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey(master.priv, keypath.keyPath).getPrivateKey require(priv.publicKey() == pub, s"derived public key doesn't match (expected=$pub actual=${priv.publicKey()}): bitcoin core may be malicious") val expectedScript = ByteVector(Script.write(Script.pay2wpkh(pub))) require(kmp2scala(input.getWitnessUtxo.publicKeyScript) == expectedScript, s"script mismatch (expected=$expectedScript, actual=${input.getWitnessUtxo.publicKeyScript}): bitcoin core may be malicious") // Update the input with the right script for a p2wpkh input, which is a *p2pkh* script, then sign and finalize. - val updated: Either[UpdateFailure, Psbt] = psbt.updateWitnessInput(psbt.getGlobal.getTx.txIn.get(pos).outPoint, input.getWitnessUtxo, null, Script.pay2pkh(pub), SigHash.SIGHASH_ALL, input.getDerivationPaths) + val updated: Either[UpdateFailure, Psbt] = psbt.updateWitnessInput(psbt.global.tx.txIn.get(pos).outPoint, input.getWitnessUtxo, null, Script.pay2pkh(pub), SigHash.SIGHASH_ALL, input.getDerivationPaths) val signed = updated.flatMap(_.sign(priv, pos)) val finalized = signed.flatMap(s => { require(s.getSig.last.toInt == SigHash.SIGHASH_ALL, "signature must end with SIGHASH_ALL") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala index baa6e62fcb..66370177c4 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala @@ -2,7 +2,7 @@ package fr.acinq.eclair.db import com.google.common.util.concurrent.ThreadFactoryBuilder import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi, TxId} import fr.acinq.eclair.channel._ import fr.acinq.eclair.db.Databases.{FileBackup, PostgresDatabases, SqliteDatabases} import fr.acinq.eclair.db.DbEventHandler.ChannelEvent @@ -11,7 +11,7 @@ import fr.acinq.eclair.payment._ import fr.acinq.eclair.payment.relay.Relayer.RelayFees import fr.acinq.eclair.router.Router import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelUpdate, NodeAddress, NodeAnnouncement} -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, Paginated, RealShortChannelId, ShortChannelId, TimestampMilli, TimestampSecond} +import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, Paginated, RealShortChannelId, ShortChannelId, TimestampMilli} import grizzled.slf4j.Logging import java.io.File @@ -99,7 +99,7 @@ case class DualNetworkDb(primary: NetworkDb, secondary: NetworkDb) extends Netwo primary.listNodes() } - override def addChannel(c: ChannelAnnouncement, txid: ByteVector32, capacity: Satoshi): Unit = { + override def addChannel(c: ChannelAnnouncement, txid: TxId, capacity: Satoshi): Unit = { runAsync(secondary.addChannel(c, txid, capacity)) primary.addChannel(c, txid, capacity) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/NetworkDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/NetworkDb.scala index 83fa20e341..e8d589ca34 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/NetworkDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/NetworkDb.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.db import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Satoshi, TxId} import fr.acinq.eclair.router.Router.PublicChannel import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement} import fr.acinq.eclair.{RealShortChannelId, ShortChannelId} @@ -36,7 +36,7 @@ trait NetworkDb { def listNodes(): Seq[NodeAnnouncement] - def addChannel(c: ChannelAnnouncement, txid: ByteVector32, capacity: Satoshi): Unit + def addChannel(c: ChannelAnnouncement, txid: TxId, capacity: Satoshi): Unit def updateChannel(u: ChannelUpdate): Unit diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala index 1e8ce962f5..6547012952 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala @@ -259,7 +259,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { override def add(e: TransactionPublished): Unit = withMetrics("audit/add-transaction-published", DbBackends.Postgres) { inTransaction { pg => using(pg.prepareStatement("INSERT INTO audit.transactions_published VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING")) { statement => - statement.setString(1, e.tx.txid.toHex) + statement.setString(1, e.tx.txid.value.toHex) statement.setString(2, e.channelId.toHex) statement.setString(3, e.remoteNodeId.value.toHex) statement.setLong(4, e.miningFee.toLong) @@ -273,7 +273,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { override def add(e: TransactionConfirmed): Unit = withMetrics("audit/add-transaction-confirmed", DbBackends.Postgres) { inTransaction { pg => using(pg.prepareStatement("INSERT INTO audit.transactions_confirmed VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING")) { statement => - statement.setString(1, e.tx.txid.toHex) + statement.setString(1, e.tx.txid.value.toHex) statement.setString(2, e.channelId.toHex) statement.setString(3, e.remoteNodeId.value.toHex) statement.setTimestamp(4, Timestamp.from(Instant.now())) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgNetworkDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgNetworkDb.scala index 1319f6dd1e..10d1250e17 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgNetworkDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgNetworkDb.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.db.pg -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Crypto, Satoshi, TxId} import fr.acinq.eclair.db.Monitoring.Metrics.withMetrics import fr.acinq.eclair.db.Monitoring.Tags.DbBackends import fr.acinq.eclair.db.NetworkDb @@ -182,12 +182,12 @@ class PgNetworkDb(implicit ds: DataSource) extends NetworkDb with Logging { } } - override def addChannel(c: ChannelAnnouncement, txid: ByteVector32, capacity: Satoshi): Unit = withMetrics("network/add-channel", DbBackends.Postgres) { + override def addChannel(c: ChannelAnnouncement, txid: TxId, capacity: Satoshi): Unit = withMetrics("network/add-channel", DbBackends.Postgres) { inTransaction { pg => using(pg.prepareStatement("INSERT INTO network.public_channels (short_channel_id, txid, channel_announcement, capacity_sat, channel_announcement_json) VALUES (?, ?, ?, ?, ?::JSONB) ON CONFLICT DO NOTHING")) { statement => statement.setLong(1, c.shortChannelId.toLong) - statement.setString(2, txid.toHex) + statement.setString(2, txid.value.toHex) statement.setBytes(3, channelAnnouncementCodec.encode(c).require.toByteArray) statement.setLong(4, capacity.toLong) statement.setString(5, serialization.write(c)) @@ -211,7 +211,7 @@ class PgNetworkDb(implicit ds: DataSource) extends NetworkDb with Logging { private def parseChannel(rs: ResultSet): PublicChannel = { val ann = channelAnnouncementCodec.decode(rs.getBitVectorOpt("channel_announcement").get).require.value - val txId = ByteVector32.fromValidHex(rs.getString("txid")) + val txId = TxId.fromValidHex(rs.getString("txid")) val capacity = rs.getLong("capacity_sat") val channel_update_1_opt = rs.getBitVectorOpt("channel_update_1").map(channelUpdateCodec.decode(_).require.value) val channel_update_2_opt = rs.getBitVectorOpt("channel_update_2").map(channelUpdateCodec.decode(_).require.value) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala index 4262a52358..f0decc63de 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala @@ -246,7 +246,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { override def add(e: TransactionPublished): Unit = withMetrics("audit/add-transaction-published", DbBackends.Sqlite) { using(sqlite.prepareStatement("INSERT OR IGNORE INTO transactions_published VALUES (?, ?, ?, ?, ?, ?)")) { statement => - statement.setBytes(1, e.tx.txid.toArray) + statement.setBytes(1, e.tx.txid.value.toArray) statement.setBytes(2, e.channelId.toArray) statement.setBytes(3, e.remoteNodeId.value.toArray) statement.setLong(4, e.miningFee.toLong) @@ -258,7 +258,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { override def add(e: TransactionConfirmed): Unit = withMetrics("audit/add-transaction-confirmed", DbBackends.Sqlite) { using(sqlite.prepareStatement("INSERT OR IGNORE INTO transactions_confirmed VALUES (?, ?, ?, ?)")) { statement => - statement.setBytes(1, e.tx.txid.toArray) + statement.setBytes(1, e.tx.txid.value.toArray) statement.setBytes(2, e.channelId.toArray) statement.setBytes(3, e.remoteNodeId.value.toArray) statement.setLong(4, TimestampMilli.now().toLong) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala index 77002b5697..67bad8a2c7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.db.sqlite -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Crypto, Satoshi, TxId} import fr.acinq.eclair.db.Monitoring.Metrics.withMetrics import fr.acinq.eclair.db.Monitoring.Tags.DbBackends import fr.acinq.eclair.db.NetworkDb @@ -115,10 +115,10 @@ class SqliteNetworkDb(val sqlite: Connection) extends NetworkDb with Logging { } } - override def addChannel(c: ChannelAnnouncement, txid: ByteVector32, capacity: Satoshi): Unit = withMetrics("network/add-channel", DbBackends.Sqlite) { + override def addChannel(c: ChannelAnnouncement, txid: TxId, capacity: Satoshi): Unit = withMetrics("network/add-channel", DbBackends.Sqlite) { using(sqlite.prepareStatement("INSERT OR IGNORE INTO channels VALUES (?, ?, ?, ?, NULL, NULL)")) { statement => statement.setLong(1, c.shortChannelId.toLong) - statement.setString(2, txid.toHex) + statement.setString(2, txid.value.toHex) statement.setBytes(3, channelAnnouncementCodec.encode(c).require.toByteArray) statement.setLong(4, capacity.toLong) statement.executeUpdate() @@ -136,7 +136,7 @@ class SqliteNetworkDb(val sqlite: Connection) extends NetworkDb with Logging { private def parseChannel(rs: ResultSet): PublicChannel = { val ann = channelAnnouncementCodec.decode(rs.getBitVectorOpt("channel_announcement").get).require.value - val txId = ByteVector32.fromValidHex(rs.getString("txid")) + val txId = TxId.fromValidHex(rs.getString("txid")) val capacity = rs.getLong("capacity_sat") val channel_update_1_opt = rs.getBitVectorOpt("channel_update_1").map(channelUpdateCodec.decode(_).require.value) val channel_update_2_opt = rs.getBitVectorOpt("channel_update_2").map(channelUpdateCodec.decode(_).require.value) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index 7f2cc36a2f..63993e5291 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -23,7 +23,7 @@ import akka.event.Logging.MDC import akka.event.{BusLogging, DiagnosticLoggingAdapter} import akka.util.Timeout import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi, SatoshiLong, TxId} import fr.acinq.eclair.Logs.LogCategory import fr.acinq.eclair.NotificationsLogger.NotifyNodeOperator import fr.acinq.eclair._ @@ -526,7 +526,7 @@ object Peer { * double-spend the funding transaction. Callers must wait for on-chain confirmations if they want guarantees that * the channel has been opened. */ - case class Created(channelId: ByteVector32, fundingTxId: ByteVector32, fee: Satoshi) extends OpenChannelResponse { override def toString = s"created channel $channelId with fundingTxId=$fundingTxId and fees=$fee" } + case class Created(channelId: ByteVector32, fundingTxId: TxId, fee: Satoshi) extends OpenChannelResponse { override def toString = s"created channel $channelId with fundingTxId=$fundingTxId and fees=$fee" } case class Rejected(reason: String) extends OpenChannelResponse { override def toString = reason } case object Cancelled extends OpenChannelResponse { override def toString = "channel creation cancelled" } case object Disconnected extends OpenChannelResponse { override def toString = "disconnected" } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala index e52417c008..e0f2edc4e9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.io import akka.actor.{ActorRef, FSM, OneForOneStrategy, PoisonPill, Props, Stash, SupervisorStrategy, Terminated} import akka.event.Logging.MDC -import fr.acinq.bitcoin.scalacompat.ByteVector32 +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.eclair.Logs.LogCategory import fr.acinq.eclair.crypto.Noise.KeyPair @@ -555,8 +555,8 @@ object PeerConnection { case object Nothing extends Data case class AuthenticatingData(pendingAuth: PendingAuth, transport: ActorRef, isPersistent: Boolean) extends Data with HasTransport case class BeforeInitData(remoteNodeId: PublicKey, pendingAuth: PendingAuth, transport: ActorRef, isPersistent: Boolean) extends Data with HasTransport - case class InitializingData(chainHash: ByteVector32, pendingAuth: PendingAuth, remoteNodeId: PublicKey, transport: ActorRef, peer: ActorRef, localInit: protocol.Init, doSync: Boolean, isPersistent: Boolean) extends Data with HasTransport - case class ConnectedData(chainHash: ByteVector32, remoteNodeId: PublicKey, transport: ActorRef, peer: ActorRef, localInit: protocol.Init, remoteInit: protocol.Init, rebroadcastDelay: FiniteDuration, gossipTimestampFilter: Option[GossipTimestampFilter] = None, behavior: Behavior = Behavior(), expectedPong_opt: Option[ExpectedPong] = None, isPersistent: Boolean) extends Data with HasTransport + case class InitializingData(chainHash: BlockHash, pendingAuth: PendingAuth, remoteNodeId: PublicKey, transport: ActorRef, peer: ActorRef, localInit: protocol.Init, doSync: Boolean, isPersistent: Boolean) extends Data with HasTransport + case class ConnectedData(chainHash: BlockHash, remoteNodeId: PublicKey, transport: ActorRef, peer: ActorRef, localInit: protocol.Init, remoteInit: protocol.Init, rebroadcastDelay: FiniteDuration, gossipTimestampFilter: Option[GossipTimestampFilter] = None, behavior: Behavior = Behavior(), expectedPong_opt: Option[ExpectedPong] = None, isPersistent: Boolean) extends Data with HasTransport case class ExpectedPong(ping: Ping, timestamp: TimestampMilli = TimestampMilli.now()) case class PingTimeout(ping: Ping) @@ -572,7 +572,7 @@ object PeerConnection { def outgoing: Boolean = remoteNodeId_opt.isDefined // if this is an outgoing connection, we know the node id in advance } case class Authenticated(peerConnection: ActorRef, remoteNodeId: PublicKey, outgoing: Boolean) extends RemoteTypes - case class InitializeConnection(peer: ActorRef, chainHash: ByteVector32, features: Features[InitFeature], doSync: Boolean) extends RemoteTypes + case class InitializeConnection(peer: ActorRef, chainHash: BlockHash, features: Features[InitFeature], doSync: Boolean) extends RemoteTypes case class ConnectionReady(peerConnection: ActorRef, remoteNodeId: PublicKey, address: NodeAddress, outgoing: Boolean, localInit: protocol.Init, remoteInit: protocol.Init) extends RemoteTypes sealed trait ConnectionResult extends RemoteTypes diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala index c093cdd575..9a0d6e4a2b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.json import com.google.common.net.HostAndPort import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath -import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, ByteVector64, OutPoint, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockHash, BlockId, Btc, ByteVector32, ByteVector64, OutPoint, Satoshi, Transaction, TxId} import fr.acinq.eclair.balance.CheckBalance.{CorrectedOnChainBalance, GlobalBalance, OffChainBalance} import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel._ @@ -118,6 +118,34 @@ object ByteVector32KmpSerializer extends MinimalSerializer({ case x: fr.acinq.bitcoin.ByteVector32 => JString(x.toHex) }) +object TxIdSerializer extends MinimalSerializer({ + case x: TxId => JString(x.value.toHex) +}) + +object TxIdKeySerializer extends MinimalKeySerializer({ + case x: TxId => x.value.toHex +}) + +object TxIdKmpSerializer extends MinimalSerializer({ + case x: fr.acinq.bitcoin.TxId => JString(x.value.toHex) +}) + +object BlockIdSerializer extends MinimalSerializer({ + case x: BlockId => JString(x.value.toHex) +}) + +object BlockIdKmpSerializer extends MinimalSerializer({ + case x: fr.acinq.bitcoin.BlockId => JString(x.value.toHex) +}) + +object BlockHashSerializer extends MinimalSerializer({ + case x: BlockHash => JString(x.value.toHex) +}) + +object BlockHashKmpSerializer extends MinimalSerializer({ + case x: fr.acinq.bitcoin.BlockHash => JString(x.value.toHex) +}) + object ByteVector64Serializer extends MinimalSerializer({ case x: ByteVector64 => JString(x.toHex) }) @@ -217,7 +245,7 @@ object CommandResponseSerializer extends MinimalSerializer({ object TransactionSerializer extends MinimalSerializer({ case x: Transaction => JObject(List( - JField("txid", JString(x.txid.toHex)), + JField("txid", JString(x.txid.value.toHex)), JField("tx", JString(x.toString())) )) }) @@ -228,34 +256,34 @@ object KeyPathSerializer extends MinimalSerializer({ object TransactionWithInputInfoSerializer extends MinimalSerializer({ case x: HtlcSuccessTx => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())), JField("paymentHash", JString(x.paymentHash.toString())), JField("htlcId", JLong(x.htlcId)), JField("confirmBeforeBlock", JLong(x.confirmationTarget.confirmBefore.toLong)) )) case x: HtlcTimeoutTx => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())), JField("htlcId", JLong(x.htlcId)), JField("confirmBeforeBlock", JLong(x.confirmationTarget.confirmBefore.toLong)) )) case x: ClaimHtlcSuccessTx => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())), JField("paymentHash", JString(x.paymentHash.toString())), JField("htlcId", JLong(x.htlcId)), JField("confirmBeforeBlock", JLong(x.confirmationTarget.confirmBefore.toLong)) )) case x: ClaimHtlcTx => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())), JField("htlcId", JLong(x.htlcId)), JField("confirmBeforeBlock", JLong(x.confirmationTarget.confirmBefore.toLong)) )) case x: ClosingTx => val txFields = List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())) ) x.toLocalOutput match { @@ -269,7 +297,7 @@ object TransactionWithInputInfoSerializer extends MinimalSerializer({ case None => JObject(txFields) } case x: ReplaceableTransactionWithInputInfo => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())), x.confirmationTarget match { case ConfirmationTarget.Absolute(confirmBefore) => JField("confirmBeforeBlock", JLong(confirmBefore.toLong)) @@ -278,7 +306,7 @@ object TransactionWithInputInfoSerializer extends MinimalSerializer({ )) case x: TransactionWithInputInfo => JObject(List( - JField("txid", JString(x.tx.txid.toHex)), + JField("txid", JString(x.tx.txid.value.toHex)), JField("tx", JString(x.tx.toString())) )) }) @@ -528,7 +556,7 @@ object ShortIdsSerializer extends ConvertClassSerializer[ShortIds](s => ShortIds // @formatter:on // @formatter:off -private case class FundingTxStatusJson(status: String, txid: Option[ByteVector32]) +private case class FundingTxStatusJson(status: String, txid: Option[TxId]) object FundingTxStatusSerializer extends ConvertClassSerializer[LocalFundingStatus]({ case s: LocalFundingStatus.UnconfirmedFundingTx => FundingTxStatusJson("unconfirmed", s.signedTx_opt.map(_.txid)) case s: LocalFundingStatus.ConfirmedFundingTx => FundingTxStatusJson("confirmed", s.signedTx_opt.map(_.txid)) @@ -634,6 +662,9 @@ object JsonSerializers { TypedActorRefSerializer + ByteVectorSerializer + ByteVector32Serializer + + TxIdSerializer + + BlockIdSerializer + + BlockHashSerializer + ByteVector64Serializer + ChannelEventSerializer + UInt64Serializer + @@ -676,6 +707,7 @@ object JsonSerializers { JavaUUIDSerializer + OriginSerializer + ByteVector32KeySerializer + + TxIdKeySerializer + GlobalBalanceSerializer + PeerInfoSerializer + PaymentFailedSummarySerializer + diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 648d1f37f7..3f0f470f76 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -16,7 +16,6 @@ package fr.acinq -import fr.acinq.bitcoin.Bitcoin import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey import fr.acinq.bitcoin.scalacompat.KotlinUtils._ import fr.acinq.bitcoin.scalacompat._ @@ -25,8 +24,6 @@ import fr.acinq.eclair.payment.relay.Relayer.RelayFees import scodec.Attempt import scodec.bits.{BitVector, ByteVector} -import scala.jdk.CollectionConverters.CollectionHasAsScala - package object eclair { val randomGen = new StrongRandom() @@ -45,8 +42,9 @@ package object eclair { def randomLong(): Long = randomGen.nextLong() - def toLongId(fundingTxHash: ByteVector32, fundingOutputIndex: Int): ByteVector32 = { - require(fundingOutputIndex < 65536, "fundingOutputIndex must not be greater than FFFF") + def toLongId(fundingTxId: TxId, fundingOutputIndex: Int): ByteVector32 = { + require(fundingOutputIndex < 65536, "fundingOutputIndex must not be greater than 0xFFFF") + val fundingTxHash = TxHash(fundingTxId).value val channelId = ByteVector32(fundingTxHash.take(30) :+ (fundingTxHash(30) ^ (fundingOutputIndex >> 8)).toByte :+ (fundingTxHash(31) ^ fundingOutputIndex).toByte) channelId } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt11Invoice.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt11Invoice.scala index 027f217f9e..04896da44c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt11Invoice.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt11Invoice.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.payment import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto} import fr.acinq.bitcoin.{Base58, Base58Check, Bech32} import fr.acinq.eclair.{Bolt11Feature, CltvExpiryDelta, Feature, FeatureSupport, Features, InvoiceFeature, MilliSatoshi, MilliSatoshiLong, ShortChannelId, TimestampSecond, randomBytes32} import scodec.bits.{BitVector, ByteOrdering, ByteVector} @@ -144,7 +144,7 @@ object Bolt11Invoice { val defaultFeatures: Features[Bolt11Feature] = Features((Features.VariableLengthOnion, FeatureSupport.Mandatory), (Features.PaymentSecret, FeatureSupport.Mandatory)) - def apply(chainHash: ByteVector32, + def apply(chainHash: BlockHash, amount: Option[MilliSatoshi], paymentHash: ByteVector32, privateKey: PrivateKey, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt12Invoice.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt12Invoice.scala index 5963479bc4..e65811560c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt12Invoice.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt12Invoice.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.payment import fr.acinq.bitcoin.Bech32 import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, ByteVector64, Crypto} import fr.acinq.eclair.crypto.Sphinx import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.BlindedRoute import fr.acinq.eclair.wire.protocol.OfferTypes._ @@ -191,7 +191,7 @@ object MinimalBolt12Invoice { val hrp = "lndi" def apply(offer: Offer, - chain: ByteVector32, + chain: BlockHash, amount: MilliSatoshi, quantity: Long, paymentHash: ByteVector32, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/send/OfferPayment.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/send/OfferPayment.scala index 2fc19f0703..8dc23a4db9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/send/OfferPayment.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/send/OfferPayment.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.payment.send import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.{ActorContext, Behaviors} import akka.actor.{ActorRef, typed} -import fr.acinq.bitcoin.scalacompat.ByteVector32 +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.BlindedRoute import fr.acinq.eclair.message.Postman.{OnionMessageResponse, SendMessage} @@ -40,7 +40,7 @@ object OfferPayment { case class UnsupportedFeatures(features: Features[InvoiceFeature]) extends Failure - case class UnsupportedChains(chains: Seq[ByteVector32]) extends Failure + case class UnsupportedChains(chains: Seq[BlockHash]) extends Failure case class ExpiredOffer(expiryDate: TimestampSecond) extends Failure diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala index 01b634a0f4..4fb6e472cb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala @@ -149,7 +149,7 @@ object EclairInternalsSerializer { def initializeConnectionCodec(system: ExtendedActorSystem): Codec[PeerConnection.InitializeConnection] = ( ("peer" | actorRefCodec(system)) :: - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("features" | variableSizeBytes(uint16, initFeaturesCodec)) :: ("doSync" | bool(8))).as[PeerConnection.InitializeConnection] @@ -164,7 +164,7 @@ object EclairInternalsSerializer { val optionQueryChannelRangeTlv: Codec[Option[QueryChannelRangeTlv]] = variableSizeBytes(uint16, optional(bool(8), variableSizeBytesLong(varintoverflow, queryFlagsCodec.upcast[QueryChannelRangeTlv]))) def sendChannelQueryCodec(system: ExtendedActorSystem): Codec[SendChannelQuery] = ( - ("chainsHash" | bytes32) :: + ("chainHash" | blockHash) :: ("remoteNodeId" | publicKey) :: ("to" | actorRefCodec(system)) :: ("replacePrevious" | bool(8)) :: diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala index fe11bf8c6d..b1c4f99639 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.router import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, sha256, verifySignature} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, LexicographicalOrdering} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector64, Crypto, LexicographicalOrdering} import fr.acinq.eclair.wire.protocol._ import fr.acinq.eclair.{CltvExpiryDelta, Feature, Features, MilliSatoshi, NodeFeature, RealShortChannelId, ShortChannelId, TimestampSecond, TimestampSecondLong, serializationResult} import scodec.bits.ByteVector @@ -28,16 +28,16 @@ import shapeless.HNil */ object Announcements { - def channelAnnouncementWitnessEncode(chainHash: ByteVector32, shortChannelId: RealShortChannelId, nodeId1: PublicKey, nodeId2: PublicKey, bitcoinKey1: PublicKey, bitcoinKey2: PublicKey, features: Features[Feature], tlvStream: TlvStream[ChannelAnnouncementTlv]): ByteVector = + def channelAnnouncementWitnessEncode(chainHash: BlockHash, shortChannelId: RealShortChannelId, nodeId1: PublicKey, nodeId2: PublicKey, bitcoinKey1: PublicKey, bitcoinKey2: PublicKey, features: Features[Feature], tlvStream: TlvStream[ChannelAnnouncementTlv]): ByteVector = sha256(sha256(serializationResult(LightningMessageCodecs.channelAnnouncementWitnessCodec.encode(features :: chainHash :: shortChannelId :: nodeId1 :: nodeId2 :: bitcoinKey1 :: bitcoinKey2 :: tlvStream :: HNil)))) def nodeAnnouncementWitnessEncode(timestamp: TimestampSecond, nodeId: PublicKey, rgbColor: Color, alias: String, features: Features[Feature], addresses: List[NodeAddress], tlvStream: TlvStream[NodeAnnouncementTlv]): ByteVector = sha256(sha256(serializationResult(LightningMessageCodecs.nodeAnnouncementWitnessCodec.encode(features :: timestamp :: nodeId :: rgbColor :: alias :: addresses :: tlvStream :: HNil)))) - def channelUpdateWitnessEncode(chainHash: ByteVector32, shortChannelId: ShortChannelId, timestamp: TimestampSecond, messageFlags: ChannelUpdate.MessageFlags, channelFlags: ChannelUpdate.ChannelFlags, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, tlvStream: TlvStream[ChannelUpdateTlv]): ByteVector = + def channelUpdateWitnessEncode(chainHash: BlockHash, shortChannelId: ShortChannelId, timestamp: TimestampSecond, messageFlags: ChannelUpdate.MessageFlags, channelFlags: ChannelUpdate.ChannelFlags, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, tlvStream: TlvStream[ChannelUpdateTlv]): ByteVector = sha256(sha256(serializationResult(LightningMessageCodecs.channelUpdateWitnessCodec.encode(chainHash :: shortChannelId :: timestamp :: messageFlags :: channelFlags :: cltvExpiryDelta :: htlcMinimumMsat :: feeBaseMsat :: feeProportionalMillionths :: htlcMaximumMsat :: tlvStream :: HNil)))) - def generateChannelAnnouncementWitness(chainHash: ByteVector32, shortChannelId: RealShortChannelId, localNodeId: PublicKey, remoteNodeId: PublicKey, localFundingKey: PublicKey, remoteFundingKey: PublicKey, features: Features[Feature]): ByteVector = + def generateChannelAnnouncementWitness(chainHash: BlockHash, shortChannelId: RealShortChannelId, localNodeId: PublicKey, remoteNodeId: PublicKey, localFundingKey: PublicKey, remoteFundingKey: PublicKey, features: Features[Feature]): ByteVector = if (isNode1(localNodeId, remoteNodeId)) { channelAnnouncementWitnessEncode(chainHash, shortChannelId, localNodeId, remoteNodeId, localFundingKey, remoteFundingKey, features, TlvStream.empty) } else { @@ -46,7 +46,7 @@ object Announcements { def signChannelAnnouncement(witness: ByteVector, key: PrivateKey): ByteVector64 = Crypto.sign(witness, key) - def makeChannelAnnouncement(chainHash: ByteVector32, shortChannelId: RealShortChannelId, localNodeId: PublicKey, remoteNodeId: PublicKey, localFundingKey: PublicKey, remoteFundingKey: PublicKey, localNodeSignature: ByteVector64, remoteNodeSignature: ByteVector64, localBitcoinSignature: ByteVector64, remoteBitcoinSignature: ByteVector64): ChannelAnnouncement = { + def makeChannelAnnouncement(chainHash: BlockHash, shortChannelId: RealShortChannelId, localNodeId: PublicKey, remoteNodeId: PublicKey, localFundingKey: PublicKey, remoteFundingKey: PublicKey, localNodeSignature: ByteVector64, remoteNodeSignature: ByteVector64, localBitcoinSignature: ByteVector64, remoteBitcoinSignature: ByteVector64): ChannelAnnouncement = { val (nodeId1, nodeId2, bitcoinKey1, bitcoinKey2, nodeSignature1, nodeSignature2, bitcoinSignature1, bitcoinSignature2) = if (isNode1(localNodeId, remoteNodeId)) { (localNodeId, remoteNodeId, localFundingKey, remoteFundingKey, localNodeSignature, remoteNodeSignature, localBitcoinSignature, remoteBitcoinSignature) @@ -118,7 +118,7 @@ object Announcements { u1.htlcMinimumMsat == u2.htlcMinimumMsat && u1.htlcMaximumMsat == u2.htlcMaximumMsat - def makeChannelUpdate(chainHash: ByteVector32, nodeSecret: PrivateKey, remoteNodeId: PublicKey, shortChannelId: ShortChannelId, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, isPrivate: Boolean = false, enable: Boolean = true, timestamp: TimestampSecond = TimestampSecond.now()): ChannelUpdate = { + def makeChannelUpdate(chainHash: BlockHash, nodeSecret: PrivateKey, remoteNodeId: PublicKey, shortChannelId: ShortChannelId, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, isPrivate: Boolean = false, enable: Boolean = true, timestamp: TimestampSecond = TimestampSecond.now()): ChannelUpdate = { val messageFlags = ChannelUpdate.MessageFlags(isPrivate) val channelFlags = ChannelUpdate.ChannelFlags(isNode1 = isNode1(nodeSecret.publicKey, remoteNodeId), isEnabled = enable) val witness = channelUpdateWitnessEncode(chainHash, shortChannelId, timestamp, messageFlags, channelFlags, cltvExpiryDelta, htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, htlcMaximumMsat, TlvStream.empty) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala index 304bb6285c..9077c3e39e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala @@ -22,7 +22,7 @@ import akka.actor.{Actor, ActorLogging, ActorRef, Cancellable, Props, Terminated import akka.event.DiagnosticLoggingAdapter import akka.event.Logging.MDC import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, Satoshi, TxId} import fr.acinq.eclair.Logs.LogCategory import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher @@ -89,7 +89,7 @@ class Router(val nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Comm // watch the funding tx of all these channels // note: some of them may already have been spent, in that case we will receive the watch event immediately (channels.values ++ pruned.values).foreach { pc => - val txid = pc.fundingTxid + val txid = pc.fundingTxId val outputIndex = ShortChannelId.coordinates(pc.ann.shortChannelId).outputIndex // avoid herd effect at startup because watch-spent are intensive in terms of rpc calls to bitcoind context.system.scheduler.scheduleOnce(Random.nextLong(nodeParams.routerConf.watchSpentWindow.toSeconds).seconds) { @@ -395,7 +395,7 @@ object Router { def updateBalances(commitments: Commitments): KnownChannel def applyChannelUpdate(update: Either[LocalChannelUpdate, RemoteChannelUpdate]): KnownChannel } - case class PublicChannel(ann: ChannelAnnouncement, fundingTxid: ByteVector32, capacity: Satoshi, update_1_opt: Option[ChannelUpdate], update_2_opt: Option[ChannelUpdate], meta_opt: Option[ChannelMeta]) extends KnownChannel { + case class PublicChannel(ann: ChannelAnnouncement, fundingTxId: TxId, capacity: Satoshi, update_1_opt: Option[ChannelUpdate], update_2_opt: Option[ChannelUpdate], meta_opt: Option[ChannelMeta]) extends KnownChannel { update_1_opt.foreach(u => assert(u.channelFlags.isNode1)) update_2_opt.foreach(u => assert(!u.channelFlags.isNode1)) @@ -689,7 +689,7 @@ object Router { // @formatter:on // @formatter:off - case class SendChannelQuery(chainHash: ByteVector32, remoteNodeId: PublicKey, to: ActorRef, replacePrevious: Boolean, flags_opt: Option[QueryChannelRangeTlv]) extends RemoteTypes + case class SendChannelQuery(chainHash: BlockHash, remoteNodeId: PublicKey, to: ActorRef, replacePrevious: Boolean, flags_opt: Option[QueryChannelRangeTlv]) extends RemoteTypes case object GetRoutingState case class RoutingState(channels: Iterable[PublicChannel], nodes: Iterable[NodeAnnouncement]) case object GetRoutingStateStreaming extends RemoteTypes diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala index f10a627c42..51e88e6d64 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.router import akka.actor.{ActorContext, ActorRef} import akka.event.LoggingAdapter -import fr.acinq.bitcoin.scalacompat.ByteVector32 +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.eclair.crypto.TransportHandler import fr.acinq.eclair.router.Monitoring.{Metrics, Tags} @@ -481,7 +481,7 @@ object Sync { * @param channels channels map * @return a ReplyChannelRange object */ - def buildReplyChannelRange(chunk: ShortChannelIdsChunk, syncComplete: Boolean, chainHash: ByteVector32, defaultEncoding: EncodingType, queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags], channels: SortedMap[RealShortChannelId, PublicChannel]): ReplyChannelRange = { + def buildReplyChannelRange(chunk: ShortChannelIdsChunk, syncComplete: Boolean, chainHash: BlockHash, defaultEncoding: EncodingType, queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags], channels: SortedMap[RealShortChannelId, PublicChannel]): ReplyChannelRange = { val encoding = if (chunk.shortChannelIds.isEmpty) EncodingType.UNCOMPRESSED else defaultEncoding val (timestamps, checksums) = queryFlags_opt match { case Some(extension) if extension.wantChecksums | extension.wantTimestamps => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Validation.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Validation.scala index 25feb8c0e6..8924edf7c3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Validation.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Validation.scala @@ -21,7 +21,7 @@ import akka.actor.{ActorContext, ActorRef, typed} import akka.event.{DiagnosticLoggingAdapter, LoggingAdapter} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.Script.{pay2wsh, write} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Satoshi, TxId} import fr.acinq.eclair.ShortChannelId.outputIndex import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{UtxoStatus, ValidateRequest, ValidateResult, WatchExternalChannelSpent} @@ -156,15 +156,15 @@ object Validation { } } - private def addPublicChannel(d: Data, nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Command], ann: ChannelAnnouncement, fundingTxid: ByteVector32, capacity: Satoshi, privChan_opt: Option[PrivateChannel])(implicit ctx: ActorContext, log: DiagnosticLoggingAdapter): Data = { + private def addPublicChannel(d: Data, nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Command], ann: ChannelAnnouncement, fundingTxId: TxId, capacity: Satoshi, privChan_opt: Option[PrivateChannel])(implicit ctx: ActorContext, log: DiagnosticLoggingAdapter): Data = { implicit val sender: ActorRef = ctx.self // necessary to preserve origin when sending messages to other actors val fundingOutputIndex = outputIndex(ann.shortChannelId) - watcher ! WatchExternalChannelSpent(ctx.self, fundingTxid, fundingOutputIndex, ann.shortChannelId) + watcher ! WatchExternalChannelSpent(ctx.self, fundingTxId, fundingOutputIndex, ann.shortChannelId) ctx.system.eventStream.publish(ChannelsDiscovered(SingleChannelDiscovered(ann, capacity, None, None) :: Nil)) - nodeParams.db.network.addChannel(ann, fundingTxid, capacity) + nodeParams.db.network.addChannel(ann, fundingTxId, capacity) val pubChan = PublicChannel( ann = ann, - fundingTxid = fundingTxid, + fundingTxId = fundingTxId, capacity = capacity, update_1_opt = privChan_opt.flatMap(_.update_1_opt), update_2_opt = privChan_opt.flatMap(_.update_2_opt), diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala index 30d1a537aa..8e256eb4dd 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala @@ -108,11 +108,11 @@ object Scripts { /** * @return the number of confirmations of each parent before which the given transaction can be published. */ - def csvTimeouts(tx: Transaction): Map[ByteVector32, Long] = { + def csvTimeouts(tx: Transaction): Map[TxId, Long] = { if (tx.version < 2) { Map.empty } else { - tx.txIn.foldLeft(Map.empty[ByteVector32, Long]) { case (current, txIn) => + tx.txIn.foldLeft(Map.empty[TxId, Long]) { case (current, txIn) => val csvTimeout = sequenceToBlockHeight(txIn.sequence) if (csvTimeout > 0) { val maxCsvTimeout = math.max(csvTimeout, current.getOrElse(txIn.outPoint.txid, 0L)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala index 628f8e2843..ddf1ededb5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala @@ -17,8 +17,8 @@ package fr.acinq.eclair.wire.internal.channel.version0 import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt} -import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, Transaction, TxId, TxOut} import fr.acinq.eclair.blockchain.fee.ConfirmationTarget import fr.acinq.eclair.channel.LocalFundingStatus.SingleFundedUnconfirmedFundingTx import fr.acinq.eclair.channel._ @@ -172,7 +172,7 @@ private[channel] object ChannelCodecs0 { val remoteCommitCodec: Codec[RemoteCommit] = ( ("index" | uint64overflow) :: ("spec" | commitmentSpecCodec) :: - ("txid" | bytes32) :: + ("txid" | txId) :: ("remotePerCommitmentPoint" | publicKey)).as[RemoteCommit].decodeOnly val updateFulfillHtlcCodec: Codec[UpdateFulfillHtlc] = ( @@ -260,10 +260,10 @@ private[channel] object ChannelCodecs0 { (wire: BitVector) => originsListCodec.decode(wire).map(_.map(_.toMap)) ) - val spentListCodec: Codec[List[(OutPoint, ByteVector32)]] = listOfN(uint16, outPointCodec ~ bytes32) + val spentListCodec: Codec[List[(OutPoint, TxId)]] = listOfN(uint16, outPointCodec ~ txId) - val spentMapCodec: Codec[Map[OutPoint, ByteVector32]] = Codec[Map[OutPoint, ByteVector32]]( - (map: Map[OutPoint, ByteVector32]) => spentListCodec.encode(map.toList), + val spentMapCodec: Codec[Map[OutPoint, TxId]] = Codec[Map[OutPoint, TxId]]( + (map: Map[OutPoint, TxId]) => spentListCodec.encode(map.toList), (wire: BitVector) => spentListCodec.decode(wire).map(_.map(_.toMap)) ) @@ -335,7 +335,7 @@ private[channel] object ChannelCodecs0 { val fundingCreatedCodec: Codec[FundingCreated] = ( ("temporaryChannelId" | bytes32) :: - ("fundingTxid" | bytes32) :: + ("fundingTxHash" | txIdAsHash) :: ("fundingOutputIndex" | uint16) :: ("signature" | bytes64) :: ("tlvStream" | provide(TlvStream.empty[FundingCreatedTlv]))).as[FundingCreated] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala index 6a87cad47c..4d3d4bab63 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.wire.internal.channel.version0 import com.softwaremill.quicklens._ import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OP_CHECKMULTISIG, OP_PUSHDATA, OutPoint, Satoshi, Script, ScriptWitness, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OP_CHECKMULTISIG, OP_PUSHDATA, OutPoint, Satoshi, Script, ScriptWitness, Transaction, TxId, TxOut} import fr.acinq.eclair.blockchain.fee.ConfirmationTarget import fr.acinq.eclair.channel._ import fr.acinq.eclair.crypto.ShaChain @@ -51,10 +51,10 @@ private[channel] object ChannelTypes0 { InputInfo(input, parentTx.txOut(input.index.toInt), Nil) } - case class LocalCommitPublished(commitTx: Transaction, claimMainDelayedOutputTx: Option[Transaction], htlcSuccessTxs: List[Transaction], htlcTimeoutTxs: List[Transaction], claimHtlcDelayedTxs: List[Transaction], irrevocablySpent: Map[OutPoint, ByteVector32]) { + case class LocalCommitPublished(commitTx: Transaction, claimMainDelayedOutputTx: Option[Transaction], htlcSuccessTxs: List[Transaction], htlcTimeoutTxs: List[Transaction], claimHtlcDelayedTxs: List[Transaction], irrevocablySpent: Map[OutPoint, TxId]) { def migrate(): channel.LocalCommitPublished = { val htlcTxs = htlcSuccessTxs ++ htlcTimeoutTxs - val knownTxs: Map[ByteVector32, Transaction] = (commitTx :: claimMainDelayedOutputTx.toList ::: htlcTxs ::: claimHtlcDelayedTxs).map(tx => tx.txid -> tx).toMap + val knownTxs: Map[TxId, Transaction] = (commitTx :: claimMainDelayedOutputTx.toList ::: htlcTxs ::: claimHtlcDelayedTxs).map(tx => tx.txid -> tx).toMap // NB: irrevocablySpent may contain transactions that belong to our peer: we will drop them in this migration but // the channel will put a watch at start-up which will make us fetch the spending transaction. val irrevocablySpentNew = irrevocablySpent.collect { case (outpoint, txid) if knownTxs.contains(txid) => (outpoint, knownTxs(txid)) } @@ -71,10 +71,10 @@ private[channel] object ChannelTypes0 { } } - case class RemoteCommitPublished(commitTx: Transaction, claimMainOutputTx: Option[Transaction], claimHtlcSuccessTxs: List[Transaction], claimHtlcTimeoutTxs: List[Transaction], irrevocablySpent: Map[OutPoint, ByteVector32]) { + case class RemoteCommitPublished(commitTx: Transaction, claimMainOutputTx: Option[Transaction], claimHtlcSuccessTxs: List[Transaction], claimHtlcTimeoutTxs: List[Transaction], irrevocablySpent: Map[OutPoint, TxId]) { def migrate(): channel.RemoteCommitPublished = { val claimHtlcTxs = claimHtlcSuccessTxs ::: claimHtlcTimeoutTxs - val knownTxs: Map[ByteVector32, Transaction] = (commitTx :: claimMainOutputTx.toList ::: claimHtlcTxs).map(tx => tx.txid -> tx).toMap + val knownTxs: Map[TxId, Transaction] = (commitTx :: claimMainOutputTx.toList ::: claimHtlcTxs).map(tx => tx.txid -> tx).toMap // NB: irrevocablySpent may contain transactions that belong to our peer: we will drop them in this migration but // the channel will put a watch at start-up which will make us fetch the spending transaction. val irrevocablySpentNew = irrevocablySpent.collect { case (outpoint, txid) if knownTxs.contains(txid) => (outpoint, knownTxs(txid)) } @@ -86,9 +86,9 @@ private[channel] object ChannelTypes0 { } } - case class RevokedCommitPublished(commitTx: Transaction, claimMainOutputTx: Option[Transaction], mainPenaltyTx: Option[Transaction], htlcPenaltyTxs: List[Transaction], claimHtlcDelayedPenaltyTxs: List[Transaction], irrevocablySpent: Map[OutPoint, ByteVector32]) { + case class RevokedCommitPublished(commitTx: Transaction, claimMainOutputTx: Option[Transaction], mainPenaltyTx: Option[Transaction], htlcPenaltyTxs: List[Transaction], claimHtlcDelayedPenaltyTxs: List[Transaction], irrevocablySpent: Map[OutPoint, TxId]) { def migrate(): channel.RevokedCommitPublished = { - val knownTxs: Map[ByteVector32, Transaction] = (commitTx :: claimMainOutputTx.toList ::: mainPenaltyTx.toList ::: htlcPenaltyTxs ::: claimHtlcDelayedPenaltyTxs).map(tx => tx.txid -> tx).toMap + val knownTxs: Map[TxId, Transaction] = (commitTx :: claimMainOutputTx.toList ::: mainPenaltyTx.toList ::: htlcPenaltyTxs ::: claimHtlcDelayedPenaltyTxs).map(tx => tx.txid -> tx).toMap // NB: irrevocablySpent may contain transactions that belong to our peer: we will drop them in this migration but // the channel will put a watch at start-up which will make us fetch the spending transaction. val irrevocablySpentNew = irrevocablySpent.collect { case (outpoint, txid) if knownTxs.contains(txid) => (outpoint, knownTxs(txid)) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala index d765c9b082..9525aa4d7e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala @@ -17,8 +17,8 @@ package fr.acinq.eclair.wire.internal.channel.version1 import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt} -import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath +import fr.acinq.bitcoin.scalacompat.{OutPoint, Transaction, TxId, TxOut} import fr.acinq.eclair.blockchain.fee.ConfirmationTarget import fr.acinq.eclair.channel.LocalFundingStatus.SingleFundedUnconfirmedFundingTx import fr.acinq.eclair.channel._ @@ -135,7 +135,7 @@ private[channel] object ChannelCodecs1 { val remoteCommitCodec: Codec[RemoteCommit] = ( ("index" | uint64overflow) :: ("spec" | commitmentSpecCodec) :: - ("txid" | bytes32) :: + ("txid" | txId) :: ("remotePerCommitmentPoint" | publicKey)).as[RemoteCommit] val updateMessageCodec: Codec[UpdateMessage] = lengthDelimited(lightningMessageCodec.narrow[UpdateMessage](f => Attempt.successful(f.asInstanceOf[UpdateMessage]), g => g)) @@ -181,7 +181,7 @@ private[channel] object ChannelCodecs1 { val originsMapCodec: Codec[Map[Long, Origin]] = mapCodec(int64, originCodec) - val spentMapCodec: Codec[Map[OutPoint, ByteVector32]] = mapCodec(outPointCodec, bytes32) + val spentMapCodec: Codec[Map[OutPoint, TxId]] = mapCodec(outPointCodec, txId) val commitmentsCodec: Codec[Commitments] = ( ("channelVersion" | channelVersionCodec) >>:~ { channelVersion => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala index ccfb9b757f..f26c0adf76 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala @@ -162,7 +162,7 @@ private[channel] object ChannelCodecs2 { val remoteCommitCodec: Codec[RemoteCommit] = ( ("index" | uint64overflow) :: ("spec" | commitmentSpecCodec) :: - ("txid" | bytes32) :: + ("txid" | txId) :: ("remotePerCommitmentPoint" | publicKey)).as[RemoteCommit] val updateMessageCodec: Codec[UpdateMessage] = lengthDelimited(lightningMessageCodec.narrow[UpdateMessage](f => Attempt.successful(f.asInstanceOf[UpdateMessage]), g => g)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala index caaef720c3..f9f2309839 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala @@ -214,7 +214,7 @@ private[channel] object ChannelCodecs3 { val remoteCommitCodec: Codec[RemoteCommit] = ( ("index" | uint64overflow) :: ("spec" | commitmentSpecCodec) :: - ("txid" | bytes32) :: + ("txid" | txId) :: ("remotePerCommitmentPoint" | publicKey)).as[RemoteCommit] val updateMessageCodec: Codec[UpdateMessage] = lengthDelimited(lightningMessageCodec.narrow[UpdateMessage](f => Attempt.successful(f.asInstanceOf[UpdateMessage]), g => g)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala index fd301d0208..f742dd9388 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala @@ -395,7 +395,7 @@ private[channel] object ChannelCodecs4 { private def remoteCommitCodec(commitmentSpecCodec: Codec[CommitmentSpec]): Codec[RemoteCommit] = ( ("index" | uint64overflow) :: ("spec" | commitmentSpecCodec) :: - ("txid" | bytes32) :: + ("txid" | txId) :: ("remotePerCommitmentPoint" | publicKey)).as[RemoteCommit] private def nextRemoteCommitCodec(commitmentSpecCodec: Codec[CommitmentSpec]): Codec[NextRemoteCommit] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala index c3299374fa..a0cbfc3773 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.wire.protocol -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Satoshi, TxId} import fr.acinq.eclair.channel.{ChannelType, ChannelTypes} import fr.acinq.eclair.wire.protocol.CommonCodecs._ import fr.acinq.eclair.wire.protocol.TlvCodecs.{tlvField, tlvStream, tmillisatoshi} @@ -165,10 +165,10 @@ sealed trait ChannelReestablishTlv extends Tlv object ChannelReestablishTlv { - case class NextFundingTlv(txHash: ByteVector32) extends ChannelReestablishTlv + case class NextFundingTlv(txId: TxId) extends ChannelReestablishTlv object NextFundingTlv { - val codec: Codec[NextFundingTlv] = tlvField("funding_tx_hash" | bytes32) + val codec: Codec[NextFundingTlv] = tlvField(txIdAsHash) } val channelReestablishTlvCodec: Codec[TlvStream[ChannelReestablishTlv]] = tlvStream(discriminated[ChannelReestablishTlv].by(varint) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala index d96d8c4131..e86e8da2bc 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.wire.protocol import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Satoshi, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, ByteVector64, Satoshi, Transaction, TxHash, TxId} import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.{ChannelFlags, RealScidStatus, ShortIds} import fr.acinq.eclair.crypto.Mac32 @@ -107,6 +107,13 @@ object CommonCodecs { val sha256: Codec[ByteVector32] = bytes32 + val blockHash: Codec[BlockHash] = bytes32.as[BlockHash] + + val txId: Codec[TxId] = bytes32.as[TxId] + + /** In lightning messages, transaction IDs are usually encoded as a tx_hash, which reverses the endianness. */ + val txIdAsHash: Codec[TxId] = bytes32.xmap(b => TxId(TxHash(b)), txId => TxHash(txId).value) + val varsizebinarydata: Codec[ByteVector] = variableSizeBytes(uint16, bytes) val listofsignatures: Codec[List[ByteVector64]] = listOfN(uint16, bytes64) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala index 37be256afd..d0c8352509 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala @@ -16,9 +16,9 @@ package fr.acinq.eclair.wire.protocol -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Satoshi} +import fr.acinq.bitcoin.scalacompat.{ByteVector64, Satoshi, TxId} import fr.acinq.eclair.UInt64 -import fr.acinq.eclair.wire.protocol.CommonCodecs.{bytes32, bytes64, satoshiSigned, varint} +import fr.acinq.eclair.wire.protocol.CommonCodecs.{bytes64, satoshiSigned, txIdAsHash, varint} import fr.acinq.eclair.wire.protocol.TlvCodecs.{tlvField, tlvStream} import scodec.Codec import scodec.codecs.discriminated @@ -31,11 +31,11 @@ sealed trait TxAddInputTlv extends Tlv object TxAddInputTlv { /** When doing a splice, the initiator must provide the previous funding txId instead of the whole transaction. */ - case class SharedInputTxId(txid: ByteVector32) extends TxAddInputTlv + case class SharedInputTxId(txId: TxId) extends TxAddInputTlv val txAddInputTlvCodec: Codec[TlvStream[TxAddInputTlv]] = tlvStream(discriminated[TxAddInputTlv].by(varint) // Note that we actually encode as a tx_hash to be consistent with other lightning messages. - .typecase(UInt64(1105), tlvField(bytes32.xmap(txId => txId.reverse, (txHash: ByteVector32) => txHash.reverse).as[SharedInputTxId])) + .typecase(UInt64(1105), tlvField(txIdAsHash.as[SharedInputTxId])) ) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala index 35f9269fcc..f7790558a0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala @@ -69,7 +69,7 @@ object LightningMessageCodecs { ("tlvStream" | ChannelReestablishTlv.channelReestablishTlvCodec)).as[ChannelReestablish] val openChannelCodec: Codec[OpenChannel] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("temporaryChannelId" | bytes32) :: ("fundingSatoshis" | satoshi) :: ("pushMsat" | millisatoshi) :: @@ -90,7 +90,7 @@ object LightningMessageCodecs { ("tlvStream" | OpenChannelTlv.openTlvCodec)).as[OpenChannel] val openDualFundedChannelCodec: Codec[OpenDualFundedChannel] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("temporaryChannelId" | bytes32) :: ("fundingFeerate" | feeratePerKw) :: ("commitmentFeerate" | feeratePerKw) :: @@ -148,7 +148,7 @@ object LightningMessageCodecs { val fundingCreatedCodec: Codec[FundingCreated] = ( ("temporaryChannelId" | bytes32) :: - ("fundingTxid" | bytes32) :: + ("fundingTxHash" | txIdAsHash) :: ("fundingOutputIndex" | uint16) :: ("signature" | bytes64) :: ("tlvStream" | FundingCreatedTlv.fundingCreatedTlvCodec)).as[FundingCreated] @@ -197,7 +197,7 @@ object LightningMessageCodecs { val txSignaturesCodec: Codec[TxSignatures] = ( ("channelId" | bytes32) :: - ("txHash" | sha256) :: + ("txHash" | txIdAsHash) :: ("witnesses" | witnessesCodec) :: ("tlvStream" | TxSignaturesTlv.txSignaturesTlvCodec)).as[TxSignatures] @@ -281,7 +281,7 @@ object LightningMessageCodecs { val channelAnnouncementWitnessCodec = ("features" | lengthPrefixedFeaturesCodec) :: - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("shortChannelId" | realshortchannelid) :: ("nodeId1" | publicKey) :: ("nodeId2" | publicKey) :: @@ -317,7 +317,7 @@ object LightningMessageCodecs { val channelFlagsCodec = ("channelFlags" | (ignore(6) :: reverseBool :: reverseBool)).as[ChannelUpdate.ChannelFlags] val channelUpdateChecksumCodec = - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("shortChannelId" | shortchannelid) :: messageFlagsCodec :: channelFlagsCodec :: @@ -328,7 +328,7 @@ object LightningMessageCodecs { ("htlcMaximumMsat" | millisatoshi) val channelUpdateWitnessCodec = - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("shortChannelId" | shortchannelid) :: ("timestamp" | timestampSecond) :: messageFlagsCodec :: @@ -355,23 +355,23 @@ object LightningMessageCodecs { }((provide[EncodingType](EncodingType.COMPRESSED_ZLIB) :: zlib(list(realshortchannelid))).as[EncodedShortChannelIds]) val queryShortChannelIdsCodec: Codec[QueryShortChannelIds] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("shortChannelIds" | variableSizeBytes(uint16, encodedShortChannelIdsCodec)) :: ("tlvStream" | QueryShortChannelIdsTlv.codec)).as[QueryShortChannelIds] val replyShortChannelIdsEndCodec: Codec[ReplyShortChannelIdsEnd] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("complete" | byte) :: ("tlvStream" | ReplyShortChannelIdsEndTlv.replyShortChannelIdsEndTlvCodec)).as[ReplyShortChannelIdsEnd] val queryChannelRangeCodec: Codec[QueryChannelRange] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("firstBlock" | blockHeight) :: ("numberOfBlocks" | uint32) :: ("tlvStream" | QueryChannelRangeTlv.codec)).as[QueryChannelRange] val replyChannelRangeCodec: Codec[ReplyChannelRange] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("firstBlock" | blockHeight) :: ("numberOfBlocks" | uint32) :: ("complete" | byte) :: @@ -379,7 +379,7 @@ object LightningMessageCodecs { ("tlvStream" | ReplyChannelRangeTlv.codec)).as[ReplyChannelRange] val gossipTimestampFilterCodec: Codec[GossipTimestampFilter] = ( - ("chainHash" | bytes32) :: + ("chainHash" | blockHash) :: ("firstTimestamp" | timestampSecond) :: ("timestampRange" | uint32) :: ("tlvStream" | GossipTimestampFilterTlv.gossipTimestampFilterTlvCodec)).as[GossipTimestampFilter] @@ -418,7 +418,7 @@ object LightningMessageCodecs { val spliceLockedCodec: Codec[SpliceLocked] = ( ("channelId" | bytes32) :: - ("fundingTxid" | bytes32) :: + ("fundingTxHash" | txIdAsHash) :: ("tlvStream" | SpliceLockedTlv.spliceLockedTlvCodec)).as[SpliceLocked] val stfuCodec: Codec[Stfu] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala index 6f6f932ba7..cc1cabbf78 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.wire.protocol import com.google.common.base.Charsets import com.google.common.net.InetAddresses import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, OutPoint, Satoshi, SatoshiLong, ScriptWitness, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, ByteVector64, OutPoint, Satoshi, SatoshiLong, ScriptWitness, Transaction, TxId} import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.{ChannelFlags, ChannelType} import fr.acinq.eclair.payment.relay.Relayer @@ -47,7 +47,7 @@ sealed trait AnnouncementMessage extends RoutingMessage // <- not in the spec sealed trait HasTimestamp extends LightningMessage { def timestamp: TimestampSecond } sealed trait HasTemporaryChannelId extends LightningMessage { def temporaryChannelId: ByteVector32 } // <- not in the spec sealed trait HasChannelId extends LightningMessage { def channelId: ByteVector32 } // <- not in the spec -sealed trait HasChainHash extends LightningMessage { def chainHash: ByteVector32 } // <- not in the spec +sealed trait HasChainHash extends LightningMessage { def chainHash: BlockHash } // <- not in the spec sealed trait HasSerialId extends LightningMessage { def serialId: UInt64 } // <- not in the spec sealed trait ForbiddenMessageDuringSplice extends LightningMessage // <- not in the spec sealed trait UpdateMessage extends HtlcMessage with ForbiddenMessageDuringSplice // <- not in the spec @@ -89,7 +89,7 @@ case class TxAddInput(channelId: ByteVector32, previousTxOutput: Long, sequence: Long, tlvStream: TlvStream[TxAddInputTlv] = TlvStream.empty) extends InteractiveTxConstructionMessage with HasChannelId with HasSerialId { - val sharedInput_opt: Option[OutPoint] = tlvStream.get[TxAddInputTlv.SharedInputTxId].map(i => OutPoint(i.txid.reverse, previousTxOutput)) + val sharedInput_opt: Option[OutPoint] = tlvStream.get[TxAddInputTlv.SharedInputTxId].map(i => OutPoint(i.txId, previousTxOutput)) } object TxAddInput { @@ -116,16 +116,15 @@ case class TxComplete(channelId: ByteVector32, tlvStream: TlvStream[TxCompleteTlv] = TlvStream.empty) extends InteractiveTxConstructionMessage with HasChannelId case class TxSignatures(channelId: ByteVector32, - txHash: ByteVector32, + txId: TxId, witnesses: Seq[ScriptWitness], tlvStream: TlvStream[TxSignaturesTlv] = TlvStream.empty) extends InteractiveTxMessage with HasChannelId { - val txId: ByteVector32 = txHash.reverse val previousFundingTxSig_opt: Option[ByteVector64] = tlvStream.get[TxSignaturesTlv.PreviousFundingTxSig].map(_.sig) } object TxSignatures { def apply(channelId: ByteVector32, tx: Transaction, witnesses: Seq[ScriptWitness], previousFundingSig_opt: Option[ByteVector64]): TxSignatures = { - TxSignatures(channelId, tx.hash, witnesses, TlvStream(previousFundingSig_opt.map(TxSignaturesTlv.PreviousFundingTxSig).toSet[TxSignaturesTlv])) + TxSignatures(channelId, tx.txid, witnesses, TlvStream(previousFundingSig_opt.map(TxSignaturesTlv.PreviousFundingTxSig).toSet[TxSignaturesTlv])) } } @@ -167,10 +166,10 @@ case class ChannelReestablish(channelId: ByteVector32, yourLastPerCommitmentSecret: PrivateKey, myCurrentPerCommitmentPoint: PublicKey, tlvStream: TlvStream[ChannelReestablishTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - val nextFundingTxId_opt: Option[ByteVector32] = tlvStream.get[ChannelReestablishTlv.NextFundingTlv].map(_.txHash.reverse) + val nextFundingTxId_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.NextFundingTlv].map(_.txId) } -case class OpenChannel(chainHash: ByteVector32, +case class OpenChannel(chainHash: BlockHash, temporaryChannelId: ByteVector32, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, @@ -213,7 +212,7 @@ case class AcceptChannel(temporaryChannelId: ByteVector32, } // NB: this message is named open_channel2 in the specification. -case class OpenDualFundedChannel(chainHash: ByteVector32, +case class OpenDualFundedChannel(chainHash: BlockHash, temporaryChannelId: ByteVector32, fundingFeerate: FeeratePerKw, commitmentFeerate: FeeratePerKw, @@ -263,7 +262,7 @@ case class AcceptDualFundedChannel(temporaryChannelId: ByteVector32, } case class FundingCreated(temporaryChannelId: ByteVector32, - fundingTxHash: ByteVector32, + fundingTxId: TxId, fundingOutputIndex: Int, signature: ByteVector64, tlvStream: TlvStream[FundingCreatedTlv] = TlvStream.empty) extends ChannelMessage with HasTemporaryChannelId @@ -319,9 +318,8 @@ object SpliceAck { } case class SpliceLocked(channelId: ByteVector32, - fundingTxHash: ByteVector32, + fundingTxId: TxId, tlvStream: TlvStream[SpliceLockedTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - val fundingTxid: ByteVector32 = fundingTxHash.reverse } case class Shutdown(channelId: ByteVector32, @@ -401,7 +399,7 @@ case class ChannelAnnouncement(nodeSignature1: ByteVector64, bitcoinSignature1: ByteVector64, bitcoinSignature2: ByteVector64, features: Features[Feature], - chainHash: ByteVector32, + chainHash: BlockHash, shortChannelId: RealShortChannelId, nodeId1: PublicKey, nodeId2: PublicKey, @@ -489,7 +487,7 @@ case class NodeAnnouncement(signature: ByteVector64, } case class ChannelUpdate(signature: ByteVector64, - chainHash: ByteVector32, + chainHash: BlockHash, shortChannelId: ShortChannelId, timestamp: TimestampSecond, messageFlags: ChannelUpdate.MessageFlags, @@ -531,23 +529,23 @@ case class EncodedShortChannelIds(encoding: EncodingType, array: List[RealShortC override def toString: String = s"EncodedShortChannelIds($encoding,${array.headOption.getOrElse("")}->${array.lastOption.getOrElse("")} size=${array.size})" } -case class QueryShortChannelIds(chainHash: ByteVector32, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[QueryShortChannelIdsTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { +case class QueryShortChannelIds(chainHash: BlockHash, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[QueryShortChannelIdsTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { val queryFlags_opt: Option[QueryShortChannelIdsTlv.EncodedQueryFlags] = tlvStream.get[QueryShortChannelIdsTlv.EncodedQueryFlags] } -case class ReplyShortChannelIdsEnd(chainHash: ByteVector32, complete: Byte, tlvStream: TlvStream[ReplyShortChannelIdsEndTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash +case class ReplyShortChannelIdsEnd(chainHash: BlockHash, complete: Byte, tlvStream: TlvStream[ReplyShortChannelIdsEndTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash -case class QueryChannelRange(chainHash: ByteVector32, firstBlock: BlockHeight, numberOfBlocks: Long, tlvStream: TlvStream[QueryChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { +case class QueryChannelRange(chainHash: BlockHash, firstBlock: BlockHeight, numberOfBlocks: Long, tlvStream: TlvStream[QueryChannelRangeTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { val queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags] = tlvStream.get[QueryChannelRangeTlv.QueryFlags] } -case class ReplyChannelRange(chainHash: ByteVector32, firstBlock: BlockHeight, numberOfBlocks: Long, syncComplete: Byte, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[ReplyChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { +case class ReplyChannelRange(chainHash: BlockHash, firstBlock: BlockHeight, numberOfBlocks: Long, syncComplete: Byte, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[ReplyChannelRangeTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { val timestamps_opt: Option[ReplyChannelRangeTlv.EncodedTimestamps] = tlvStream.get[ReplyChannelRangeTlv.EncodedTimestamps] val checksums_opt: Option[ReplyChannelRangeTlv.EncodedChecksums] = tlvStream.get[ReplyChannelRangeTlv.EncodedChecksums] } object ReplyChannelRange { - def apply(chainHash: ByteVector32, + def apply(chainHash: BlockHash, firstBlock: BlockHeight, numberOfBlocks: Long, syncComplete: Byte, @@ -560,7 +558,7 @@ object ReplyChannelRange { } } -case class GossipTimestampFilter(chainHash: ByteVector32, firstTimestamp: TimestampSecond, timestampRange: Long, tlvStream: TlvStream[GossipTimestampFilterTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash +case class GossipTimestampFilter(chainHash: BlockHash, firstTimestamp: TimestampSecond, timestampRange: Long, tlvStream: TlvStream[GossipTimestampFilterTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash case class OnionMessage(blindingKey: PublicKey, onionRoutingPacket: OnionRoutingPacket, tlvStream: TlvStream[OnionMessageTlv] = TlvStream.empty) extends LightningMessage diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferCodecs.scala index 913036f8ac..f8d8a6abae 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferCodecs.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.wire.protocol -import fr.acinq.bitcoin.scalacompat.ByteVector32 +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.{BlindedNode, BlindedRoute} import fr.acinq.eclair.wire.protocol.CommonCodecs._ import fr.acinq.eclair.wire.protocol.OfferTypes.{InvoiceRequestChain, InvoiceRequestPayerNote, InvoiceRequestQuantity, _} @@ -26,7 +26,7 @@ import scodec.{Attempt, Codec, Err} import scodec.codecs._ object OfferCodecs { - private val offerChains: Codec[OfferChains] = tlvField(list(bytes32).xmap[Seq[ByteVector32]](_.toSeq, _.toList)) + private val offerChains: Codec[OfferChains] = tlvField(list(blockHash).xmap[Seq[BlockHash]](_.toSeq, _.toList)) private val offerMetadata: Codec[OfferMetadata] = tlvField(bytes) @@ -91,7 +91,7 @@ object OfferCodecs { private val invoiceRequestMetadata: Codec[InvoiceRequestMetadata] = tlvField(bytes) - private val invoiceRequestChain: Codec[InvoiceRequestChain] = tlvField(bytes32) + private val invoiceRequestChain: Codec[InvoiceRequestChain] = tlvField(blockHash) private val invoiceRequestAmount: Codec[InvoiceRequestAmount] = tlvField(tmillisatoshi) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala index 6d49408b96..3d7fa51479 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala @@ -18,12 +18,12 @@ package fr.acinq.eclair.wire.protocol import fr.acinq.bitcoin.Bech32 import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, XonlyPublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, LexicographicalOrdering} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto, LexicographicalOrdering} import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.{BlindedNode, BlindedRoute} import fr.acinq.eclair.wire.protocol.CommonCodecs.varint import fr.acinq.eclair.wire.protocol.OnionRoutingCodecs.{ForbiddenTlv, InvalidTlvPayload, MissingRequiredTlv} import fr.acinq.eclair.wire.protocol.TlvCodecs.genericTlv -import fr.acinq.eclair.{Bolt12Feature, CltvExpiryDelta, Feature, Features, MilliSatoshi, RealShortChannelId, ShortChannelId, TimestampSecond, UInt64, nodeFee, randomBytes32} +import fr.acinq.eclair.{Bolt12Feature, CltvExpiryDelta, Feature, Features, MilliSatoshi, RealShortChannelId, TimestampSecond, UInt64, nodeFee, randomBytes32} import scodec.Codec import scodec.bits.ByteVector import scodec.codecs.vector @@ -61,7 +61,7 @@ object OfferTypes { /** * Chains for which the offer is valid. If empty, bitcoin mainnet is implied. */ - case class OfferChains(chains: Seq[ByteVector32]) extends OfferTlv + case class OfferChains(chains: Seq[BlockHash]) extends OfferTlv /** * Data from the offer creator to themselves, for instance a signature that authenticates the offer so that they don't need to store the offer. @@ -125,7 +125,7 @@ object OfferTypes { /** * If `OfferChains` is present, this specifies which chain is going to be used to pay. */ - case class InvoiceRequestChain(hash: ByteVector32) extends InvoiceRequestTlv + case class InvoiceRequestChain(hash: BlockHash) extends InvoiceRequestTlv /** * Amount that the sender is going to send. @@ -216,11 +216,11 @@ object OfferTypes { case class Signature(signature: ByteVector64) extends InvoiceRequestTlv with InvoiceTlv def filterOfferFields(tlvs: TlvStream[InvoiceRequestTlv]): TlvStream[OfferTlv] = - // Offer TLVs are in the range (0, 80). + // Offer TLVs are in the range (0, 80). TlvStream[OfferTlv](tlvs.records.collect { case tlv: OfferTlv => tlv }, tlvs.unknown.filter(_.tag < UInt64(80))) def filterInvoiceRequestFields(tlvs: TlvStream[InvoiceTlv]): TlvStream[InvoiceRequestTlv] = - // Invoice request TLVs are in the range [0, 160): invoice request metadata (tag 0), offer TLVs, and additional invoice request TLVs in the range [80, 160). + // Invoice request TLVs are in the range [0, 160): invoice request metadata (tag 0), offer TLVs, and additional invoice request TLVs in the range [80, 160). TlvStream[InvoiceRequestTlv](tlvs.records.collect { case tlv: InvoiceRequestTlv => tlv }, tlvs.unknown.filter(_.tag < UInt64(160))) case class ErroneousField(tag: Long) extends InvoiceErrorTlv @@ -230,7 +230,7 @@ object OfferTypes { case class Error(message: String) extends InvoiceErrorTlv case class Offer(records: TlvStream[OfferTlv]) { - val chains: Seq[ByteVector32] = records.get[OfferChains].map(_.chains).getOrElse(Seq(Block.LivenetGenesisBlock.hash)) + val chains: Seq[BlockHash] = records.get[OfferChains].map(_.chains).getOrElse(Seq(Block.LivenetGenesisBlock.hash)) val metadata: Option[ByteVector] = records.get[OfferMetadata].map(_.data) val currency: Option[String] = records.get[OfferCurrency].map(_.iso4217) val amount: Option[MilliSatoshi] = currency match { @@ -271,7 +271,7 @@ object OfferTypes { description: String, nodeId: PublicKey, features: Features[Bolt12Feature], - chain: ByteVector32, + chain: BlockHash, additionalTlvs: Set[OfferTlv] = Set.empty, customTlvs: Set[GenericTlv] = Set.empty): Offer = { val tlvs: Set[OfferTlv] = Set( @@ -310,7 +310,7 @@ object OfferTypes { val offer: Offer = Offer.validate(filterOfferFields(records)).toOption.get val metadata: ByteVector = records.get[InvoiceRequestMetadata].get.data - val chain: ByteVector32 = records.get[InvoiceRequestChain].map(_.hash).getOrElse(Block.LivenetGenesisBlock.hash) + val chain: BlockHash = records.get[InvoiceRequestChain].map(_.hash).getOrElse(Block.LivenetGenesisBlock.hash) val amount: Option[MilliSatoshi] = records.get[InvoiceRequestAmount].map(_.amount) val features: Features[Bolt12Feature] = records.get[InvoiceRequestFeatures].map(_.features.bolt12Features()).getOrElse(Features.empty) val quantity_opt: Option[Long] = records.get[InvoiceRequestQuantity].map(_.quantity) @@ -367,7 +367,7 @@ object OfferTypes { quantity: Long, features: Features[Bolt12Feature], payerKey: PrivateKey, - chain: ByteVector32, + chain: BlockHash, additionalTlvs: Set[InvoiceRequestTlv] = Set.empty, customTlvs: Set[GenericTlv] = Set.empty): InvoiceRequest = { require(offer.chains.contains(chain)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/SetupAndControlTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/SetupAndControlTlv.scala index 6824b14674..6938381cb9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/SetupAndControlTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/SetupAndControlTlv.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.wire.protocol -import fr.acinq.bitcoin.scalacompat.ByteVector32 +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.eclair.UInt64 import fr.acinq.eclair.wire.protocol.CommonCodecs._ import fr.acinq.eclair.wire.protocol.TlvCodecs.{tlvField, tlvStream} @@ -33,7 +33,7 @@ sealed trait InitTlv extends Tlv object InitTlv { /** The chains the node is interested in. */ - case class Networks(chainHashes: List[ByteVector32]) extends InitTlv + case class Networks(chainHashes: List[BlockHash]) extends InitTlv /** * When receiving an incoming connection, we can send back the public address our peer is connecting from. @@ -47,7 +47,7 @@ object InitTlvCodecs { import InitTlv._ - private val networks: Codec[Networks] = tlvField(list(bytes32)) + private val networks: Codec[Networks] = tlvField(list(blockHash)) private val remoteAddress: Codec[RemoteAddress] = tlvField(nodeaddress) val initTlvCodec = tlvStream(discriminated[InitTlv].by(varint) diff --git a/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json index c11f0debbb..7b02159dde 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json @@ -120,7 +120,7 @@ "waitingSince" : 400000, "lastSent" : { "temporaryChannelId" : "0000000000000000000000000000000000000000000000000000000000000000", - "fundingTxHash" : "e917adc681383fe00f779c6144a1bd91135ba2c9862ad1bc5aa8a14d37bae3f4", + "fundingTxId" : "f4e3ba374da1a85abcd12a86c9a25b1391bda144619c770fe03f3881c6ad17e9", "fundingOutputIndex" : 0, "signature" : "bd55d8660f54a1be6e123e2ed9cd6669d90b830d99dc6f9addd9ae65c447ea6b657e2fe39841f66c1d6a2fc80ad59e6f3d9bfaf177f4e95a579f0683bf3e9790", "tlvStream" : { } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala index e25d69f682..57acb2891a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala @@ -22,7 +22,7 @@ import akka.pattern.pipe import akka.testkit.TestProbe import akka.util.Timeout import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, SatoshiLong, TxId} import fr.acinq.eclair.ApiTypes.{ChannelIdentifier, ChannelNotFound} import fr.acinq.eclair.TestConstants._ import fr.acinq.eclair.blockchain.DummyOnChainWallet @@ -235,7 +235,7 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I (ann_cd, makeUpdateShort(ShortChannelId(3L), c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(500))), (ann_ec, makeUpdateShort(ShortChannelId(7L), e, c, feeBase = 2 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12))) ).map { case (ann, update) => - update.shortChannelId -> PublicChannel(ann, ByteVector32.Zeroes, 100 sat, Some(update.copy(channelFlags = ChannelUpdate.ChannelFlags.DUMMY)), None, None) + update.shortChannelId -> PublicChannel(ann, TxId(ByteVector32.Zeroes), 100 sat, Some(update.copy(channelFlags = ChannelUpdate.ChannelFlags.DUMMY)), None, None) }: _*) val eclair = new EclairImpl(kit) @@ -361,8 +361,8 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I val channel1 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(1), a, b, a, b, ByteVector64.Zeroes, ByteVector64.Zeroes, ByteVector64.Zeroes, ByteVector64.Zeroes) val channel2 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(2), b, c, b, c, ByteVector64.Zeroes, ByteVector64.Zeroes, ByteVector64.Zeroes, ByteVector64.Zeroes) val publicChannels = SortedMap( - channel1.shortChannelId -> PublicChannel(channel1, ByteVector32.Zeroes, 100_000 sat, None, None, None), - channel2.shortChannelId -> PublicChannel(channel2, ByteVector32.Zeroes, 150_000 sat, None, None, None), + channel1.shortChannelId -> PublicChannel(channel1, TxId(ByteVector32.Zeroes), 100_000 sat, None, None, None), + channel2.shortChannelId -> PublicChannel(channel2, TxId(ByteVector32.Zeroes), 150_000 sat, None, None, None), ) val (channelId3, shortIds3) = (randomBytes32(), ShortIds(RealScidStatus.Unknown, Alias(13), None)) val (channelId4, shortIds4) = (randomBytes32(), ShortIds(RealScidStatus.Final(RealShortChannelId(4)), Alias(14), None)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala index dcdd7d9154..f41f552986 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Script, addressToPublicKeyScript} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Script, TxHash, TxId, addressToPublicKeyScript} import fr.acinq.bitcoin.{Base58, Base58Check, Bech32} import org.scalatest.funsuite.AnyFunSuite import scodec.bits._ @@ -32,13 +32,15 @@ class PackageSpec extends AnyFunSuite { implicit def byteVector322array(input: ByteVector32): Array[Byte] = input.toArray test("compute long channel id") { - val data = ((hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") :: - (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 1, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE") :: - (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000", 2, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0002") :: - (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00F0", 0x0F00, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0") :: Nil) - .map(x => (ByteVector32(x._1), x._2, ByteVector32(x._3))) - - data.foreach(x => assert(toLongId(ByteVector32(x._1), x._2) == x._3)) + case class TestCase(fundingTxId: TxId, fundingOutputIndex: Int, expected: ByteVector32) + + val testCases = Seq( + TestCase(TxId.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 0, ByteVector32.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")), + TestCase(TxId.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 1, ByteVector32.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")), + TestCase(TxId.fromValidHex("0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 2, ByteVector32.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0002")), + TestCase(TxId.fromValidHex("F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 0x0f00, ByteVector32.fromValidHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0")), + ) + testCases.foreach(t => assert(toLongId(t.fundingTxId, t.fundingOutputIndex) == t.expected)) } test("decode base58 addresses") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala index 25d7ee41bd..0cb8057a76 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair import akka.actor.ActorSystem -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} +import fr.acinq.bitcoin.scalacompat.{BlockId, Transaction, TxId} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinJsonRPCAuthMethod.UserPassword import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinCoreClient} @@ -32,17 +32,17 @@ class TestBitcoinCoreClient()(implicit system: ActorSystem) extends BitcoinCoreC import scala.concurrent.ExecutionContext.Implicits.global - system.scheduler.scheduleWithFixedDelay(100 milliseconds, 100 milliseconds)(() => system.eventStream.publish(NewBlock(randomBytes32()))) + system.scheduler.scheduleWithFixedDelay(100 milliseconds, 100 milliseconds)(() => system.eventStream.publish(NewBlock(BlockId(randomBytes32())))) - override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] = { + override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] = { system.eventStream.publish(NewTransaction(tx)) Future.successful(tx.txid) } - override def getTxConfirmations(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.successful(Some(10)) + override def getTxConfirmations(txId: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.successful(Some(10)) - override def getTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] = Future.failed(new RuntimeException("not implemented")) + override def getTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Transaction] = Future.failed(new RuntimeException("not implemented")) - override def getTransactionShortId(txId: ByteVector32)(implicit ec: ExecutionContext): Future[(BlockHeight, Int)] = Future.successful((BlockHeight(400000), 42)) + override def getTransactionShortId(txId: TxId)(implicit ec: ExecutionContext): Future[(BlockHeight, Int)] = Future.successful((BlockHeight(400000), 42)) } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index c8012d440b..8a81b24965 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -19,17 +19,17 @@ package fr.acinq.eclair import akka.actor.{ActorRef, ActorSystem} import akka.event.{DiagnosticLoggingAdapter, EventStream} import akka.testkit.{TestActor, TestProbe} +import fr.acinq.bitcoin.scalacompat.TxId import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.io.Peer import fr.acinq.eclair.wire.protocol.LightningMessage import org.scalatest.concurrent.Eventually.eventually -import org.scalatest.concurrent.PatienceConfiguration import java.io.File import java.net.ServerSocket import java.nio.file.Files import java.util.UUID -import scala.concurrent.duration.{DurationInt, FiniteDuration} +import scala.concurrent.duration.FiniteDuration object TestUtils { @@ -110,4 +110,6 @@ object TestUtils { def waitFor(duration: FiniteDuration): Unit = Thread.sleep(duration.toMillis) + def randomTxId(): TxId = TxId(randomBytes32()) + } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/balance/CheckBalanceSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/balance/CheckBalanceSpec.scala index 54a8c05e1e..b66fc6d7b1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/balance/CheckBalanceSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/balance/CheckBalanceSpec.scala @@ -2,7 +2,8 @@ package fr.acinq.eclair.balance import akka.pattern.pipe import akka.testkit.TestProbe -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, TxId} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.balance.CheckBalance.{ClosingBalance, MainAndHtlcBalance, OffChainBalance, PossiblyPublishedMainAndHtlcBalance, PossiblyPublishedMainBalance} import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{apply => _, _} import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient @@ -250,12 +251,12 @@ class CheckBalanceSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with } test("tx pruning") { () => - val txids = (for (_ <- 0 until 20) yield randomBytes32()).toList + val txids = (for (_ <- 0 until 20) yield randomTxId()).toList val knownTxids = Set(txids(1), txids(3), txids(4), txids(6), txids(9), txids(12), txids(13)) val bitcoinClient = new BitcoinCoreClient(null) { /** Get the number of confirmations of a given transaction. */ - override def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = + override def getTxConfirmations(txid: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.successful(if (knownTxids.contains(txid)) Some(42) else None) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/DummyOnChainWallet.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/DummyOnChainWallet.scala index 8caca5b45b..4e02548273 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/DummyOnChainWallet.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/DummyOnChainWallet.scala @@ -19,13 +19,14 @@ package fr.acinq.eclair.blockchain import fr.acinq.bitcoin.TxIn.SEQUENCE_FINAL import fr.acinq.bitcoin.psbt.Psbt import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, OutPoint, Satoshi, SatoshiLong, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.scalacompat.{Crypto, OutPoint, Satoshi, SatoshiLong, Script, Transaction, TxId, TxIn, TxOut} import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse, OnChainBalance, ProcessPsbtResponse} import fr.acinq.eclair.blockchain.bitcoind.BitcoindService.SignTransactionResponse import fr.acinq.eclair.blockchain.fee.FeeratePerKw +import fr.acinq.eclair.randomKey import fr.acinq.eclair.transactions.Transactions -import fr.acinq.eclair.{randomBytes32, randomKey} import scodec.bits._ import scala.concurrent.{ExecutionContext, Future, Promise} @@ -38,8 +39,8 @@ class DummyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { import DummyOnChainWallet._ - val funded = collection.concurrent.TrieMap.empty[ByteVector32, Transaction] - val published = collection.concurrent.TrieMap.empty[ByteVector32, Transaction] + val funded = collection.concurrent.TrieMap.empty[TxId, Transaction] + val published = collection.concurrent.TrieMap.empty[TxId, Transaction] var rolledback = Set.empty[Transaction] override def onChainBalance()(implicit ec: ExecutionContext): Future[OnChainBalance] = Future.successful(OnChainBalance(1105 sat, 561 sat)) @@ -55,7 +56,7 @@ class DummyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { override def signPsbt(psbt: Psbt, ourInputs: Seq[Int], ourOutputs: Seq[Int])(implicit ec: ExecutionContext): Future[ProcessPsbtResponse] = Future.successful(ProcessPsbtResponse(psbt, complete = true)) - override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] = { + override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] = { published += (tx.txid -> tx) Future.successful(tx.txid) } @@ -68,9 +69,9 @@ class DummyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { override def commit(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = publishTransaction(tx).map(_ => true) - override def getTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] = Future.failed(new RuntimeException("transaction not found")) + override def getTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Transaction] = Future.failed(new RuntimeException("transaction not found")) - override def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.failed(new RuntimeException("transaction not found")) + override def getTxConfirmations(txid: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.failed(new RuntimeException("transaction not found")) override def rollback(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = { rolledback = rolledback + tx @@ -87,7 +88,7 @@ class NoOpOnChainWallet extends OnChainWallet with OnchainPubkeyCache { import DummyOnChainWallet._ var rolledback = Seq.empty[Transaction] - var doubleSpent = Set.empty[ByteVector32] + var doubleSpent = Set.empty[TxId] override def onChainBalance()(implicit ec: ExecutionContext): Future[OnChainBalance] = Future.successful(OnChainBalance(1105 sat, 561 sat)) @@ -99,15 +100,15 @@ class NoOpOnChainWallet extends OnChainWallet with OnchainPubkeyCache { override def signPsbt(psbt: Psbt, ourInputs: Seq[Int], ourOutputs: Seq[Int])(implicit ec: ExecutionContext): Future[ProcessPsbtResponse] = Promise().future // will never be completed - override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] = Future.successful(tx.txid) + override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] = Future.successful(tx.txid) override def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRatePerKw: FeeratePerKw)(implicit ec: ExecutionContext): Future[MakeFundingTxResponse] = Promise().future // will never be completed override def commit(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = Future.successful(true) - override def getTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] = Promise().future // will never be completed + override def getTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Transaction] = Promise().future // will never be completed - override def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = Promise().future // will never be completed + override def getTxConfirmations(txid: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = Promise().future // will never be completed override def rollback(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = { rolledback = rolledback :+ tx @@ -125,7 +126,7 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { // We create a new dummy input transaction for every funding request. var inputs = Seq.empty[Transaction] var rolledback = Seq.empty[Transaction] - var doubleSpent = Set.empty[ByteVector32] + var doubleSpent = Set.empty[TxId] override def onChainBalance()(implicit ec: ExecutionContext): Future[OnChainBalance] = Future.successful(OnChainBalance(1105 sat, 561 sat)) @@ -138,7 +139,7 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { val amountOut = tx.txOut.map(_.amount).sum // We add a single input to reach the desired feerate. val inputAmount = amountOut + 100_000.sat - val inputTx = Transaction(2, Seq(TxIn(OutPoint(randomBytes32(), 1), Nil, 0)), Seq(TxOut(inputAmount, Script.pay2wpkh(pubkey))), 0) + val inputTx = Transaction(2, Seq(TxIn(OutPoint(randomTxId(), 1), Nil, 0)), Seq(TxOut(inputAmount, Script.pay2wpkh(pubkey))), 0) inputs = inputs :+ inputTx val dummyWitness = Script.witnessPay2wpkh(pubkey, ByteVector.fill(73)(0)) val dummySignedTx = tx.copy( @@ -166,7 +167,7 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { Future.successful(SignTransactionResponse(signedTx, complete)) } - override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[ByteVector32] = { + override def publishTransaction(tx: Transaction)(implicit ec: ExecutionContext): Future[TxId] = { inputs = inputs :+ tx Future.successful(tx.txid) } @@ -174,7 +175,7 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { override def signPsbt(psbt: Psbt, ourInputs: Seq[Int], ourOutputs: Seq[Int])(implicit ec: ExecutionContext): Future[ProcessPsbtResponse] = { import fr.acinq.bitcoin.scalacompat.KotlinUtils._ - val tx: Transaction = psbt.getGlobal.getTx + val tx: Transaction = psbt.global.tx val signedPsbt = tx.txIn.zipWithIndex.foldLeft(new Psbt(tx)) { case (currentPsbt, (txIn, index)) => inputs.find(_.txid == txIn.outPoint.txid) match { case Some(inputTx) => @@ -198,14 +199,14 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnchainPubkeyCache { override def commit(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = Future.successful(true) - override def getTransaction(txId: ByteVector32)(implicit ec: ExecutionContext): Future[Transaction] = synchronized { + override def getTransaction(txId: TxId)(implicit ec: ExecutionContext): Future[Transaction] = synchronized { inputs.find(_.txid == txId) match { case Some(tx) => Future.successful(tx) case None => Future.failed(new RuntimeException(s"txid=$txId not found")) } } - override def getTxConfirmations(txid: ByteVector32)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.successful(None) + override def getTxConfirmations(txid: TxId)(implicit ec: ExecutionContext): Future[Option[Int]] = Future.successful(None) override def rollback(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = { rolledback = rolledback :+ tx @@ -225,7 +226,7 @@ object DummyOnChainWallet { def makeDummyFundingTx(pubkeyScript: ByteVector, amount: Satoshi): MakeFundingTxResponse = { val fundingTx = Transaction( version = 2, - txIn = TxIn(OutPoint(ByteVector32(ByteVector.fill(32)(1)), 42), signatureScript = Nil, sequence = SEQUENCE_FINAL) :: Nil, + txIn = TxIn(OutPoint(TxId.fromValidHex("0101010101010101010101010101010101010101010101010101010101010101"), 42), signatureScript = Nil, sequence = SEQUENCE_FINAL) :: Nil, txOut = TxOut(amount, pubkeyScript) :: Nil, lockTime = 0 ) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala index 6d0312782c..2ad2874949 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala @@ -22,8 +22,9 @@ import akka.testkit.TestProbe import fr.acinq.bitcoin import fr.acinq.bitcoin.psbt.{Psbt, UpdateFailure} import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, Btc, BtcDouble, ByteVector32, Crypto, DeterministicWallet, MilliBtcDouble, MnemonicCode, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, addressFromPublicKeyScript, addressToPublicKeyScript, computeBIP84Address, computeP2PkhAddress, computeP2WpkhAddress} +import fr.acinq.bitcoin.scalacompat.{Block, Btc, BtcDouble, ByteVector32, Crypto, DeterministicWallet, MilliBtcDouble, MnemonicCode, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, addressFromPublicKeyScript, addressToPublicKeyScript, computeBIP84Address, computeP2PkhAddress, computeP2WpkhAddress} import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse, OnChainBalance, ProcessPsbtResponse} import fr.acinq.eclair.blockchain.WatcherSpec.{createSpendManyP2WPKH, createSpendP2WPKH} import fr.acinq.eclair.blockchain.bitcoind.BitcoindService.{BitcoinReq, SignTransactionResponse} @@ -198,7 +199,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A walletExternalFunds.getReceiveAddress().pipeTo(sender.ref) val walletAddress = sender.expectMsgType[String] defaultWallet.sendToPubkeyScript(Script.write(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, walletAddress).toOption.get), amount, FeeratePerKw(FeeratePerByte(3.sat))).pipeTo(sender.ref) - sender.expectMsgType[ByteVector32] + sender.expectMsgType[TxId] }) // We receive more funds on an address that does not belong to our wallet. @@ -664,7 +665,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A val nonWalletWitness = ScriptWitness(Seq(nonWalletSig, nonWalletKey.publicKey.value)) val txWithSignedNonWalletInput = txWithNonWalletInput.updateWitness(0, nonWalletWitness) val psbt = new Psbt(txWithSignedNonWalletInput) - val updated: Either[UpdateFailure, Psbt] = psbt.updateWitnessInput(psbt.getGlobal.getTx.txIn.get(0).outPoint, txToRemote.txOut(0), null, fr.acinq.bitcoin.Script.pay2pkh(nonWalletKey.publicKey), SigHash.SIGHASH_ALL, psbt.getInput(0).getDerivationPaths) + val updated: Either[UpdateFailure, Psbt] = psbt.updateWitnessInput(psbt.global.tx.txIn.get(0).outPoint, txToRemote.txOut(0), null, fr.acinq.bitcoin.Script.pay2pkh(nonWalletKey.publicKey), SigHash.SIGHASH_ALL, psbt.getInput(0).getDerivationPaths) val Right(psbt1) = updated.flatMap(_.finalizeWitnessInput(0, nonWalletWitness)) bitcoinClient.signPsbt(psbt1, txWithSignedNonWalletInput.txIn.indices.tail, Nil).pipeTo(sender.ref) val signTxResponse2 = sender.expectMsgType[ProcessPsbtResponse] @@ -696,7 +697,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A val nonWalletWitness = ScriptWitness(Seq(nonWalletSig, nonWalletKey.publicKey.value)) val txWithSignedUnconfirmedInput = txWithUnconfirmedInput.updateWitness(0, nonWalletWitness) val psbt = new Psbt(txWithSignedUnconfirmedInput) - val Right(psbt1) = psbt.updateWitnessInput(psbt.getGlobal.getTx.txIn.get(0).outPoint, unconfirmedTx.txOut(0), null, fr.acinq.bitcoin.Script.pay2pkh(nonWalletKey.publicKey), SigHash.SIGHASH_ALL, psbt.getInput(0).getDerivationPaths) + val Right(psbt1) = psbt.updateWitnessInput(psbt.global.tx.txIn.get(0).outPoint, unconfirmedTx.txOut(0), null, fr.acinq.bitcoin.Script.pay2pkh(nonWalletKey.publicKey), SigHash.SIGHASH_ALL, psbt.getInput(0).getDerivationPaths) .flatMap(_.finalizeWitnessInput(0, nonWalletWitness)) bitcoinClient.signPsbt(psbt1, txWithSignedUnconfirmedInput.txIn.indices.tail, Nil).pipeTo(sender.ref) assert(sender.expectMsgType[ProcessPsbtResponse].complete) @@ -733,7 +734,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A val spendingTx = { val address = getNewAddress(sender) val pos = if (changePos == 0) 1 else 0 - bitcoinrpcclient.invoke("createrawtransaction", Array(Map("txid" -> tx.txid.toHex, "vout" -> pos)), Map(address -> 5.999)).pipeTo(sender.ref) + bitcoinrpcclient.invoke("createrawtransaction", Array(Map("txid" -> tx.txid.value.toHex, "vout" -> pos)), Map(address -> 5.999)).pipeTo(sender.ref) val JString(unsignedTxStr) = sender.expectMsgType[JValue] val unsignedTx = Transaction.read(unsignedTxStr) val sig = Transaction.signInput(unsignedTx, 0, Script.pay2pkh(priv.publicKey), bitcoin.SigHash.SIGHASH_ALL, 6.btc.toSatoshi, bitcoin.SigVersion.SIGVERSION_WITNESS_V0, priv) @@ -1026,7 +1027,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A signTxResponse.tx } - def getMempoolTx(txid: ByteVector32): MempoolTx = { + def getMempoolTx(txid: TxId): MempoolTx = { val probe = TestProbe() bitcoinClient.getMempoolTx(txid).pipeTo(probe.ref) probe.expectMsgType[MempoolTx] @@ -1090,7 +1091,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A test("cannot bump transaction fees (unknown transaction)") { val sender = TestProbe() val bitcoinClient = makeBitcoinCoreClient() - bitcoinClient.cpfp(Set(OutPoint(randomBytes32(), 0), OutPoint(randomBytes32(), 3)), FeeratePerKw(1500 sat)).pipeTo(sender.ref) + bitcoinClient.cpfp(Set(OutPoint(randomTxId(), 0), OutPoint(randomTxId(), 3)), FeeratePerKw(1500 sat)).pipeTo(sender.ref) val failure = sender.expectMsgType[Failure] assert(failure.cause.getMessage.contains("some transactions could not be found")) } @@ -1328,7 +1329,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A val pubKey = randomKey().publicKey val legacyAddress = computeP2PkhAddress(pubKey, Block.RegtestGenesisBlock.hash) bitcoinClient.sendToPubkeyScript(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, legacyAddress).toOption.get, 150_000 sat, FeeratePerKw(FeeratePerByte(3.sat))).pipeTo(sender.ref) - val txId = sender.expectMsgType[ByteVector32] + val txId = sender.expectMsgType[TxId] bitcoinClient.getTransaction(txId).pipeTo(sender.ref) val tx = sender.expectMsgType[Transaction] // We have a change output. @@ -1468,7 +1469,7 @@ class BitcoinCoreClientWithEclairSignerSpec extends BitcoinCoreClientSpec { assert(error.cause.getMessage.contains("Private keys are disabled for this wallet")) wallet.sendToPubkeyScript(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).toOption.get, 50_000.sat, FeeratePerKw(FeeratePerByte(5.sat))).pipeTo(sender.ref) - sender.expectMsgType[ByteVector32] + sender.expectMsgType[TxId] } } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcherSpec.scala index 1584316b1f..ff13d282a1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcherSpec.scala @@ -21,7 +21,8 @@ import akka.actor.typed.scaladsl.adapter.{ClassicActorSystemOps, TypedActorRefOp import akka.actor.{ActorRef, Props, typed} import akka.pattern.pipe import akka.testkit.TestProbe -import fr.acinq.bitcoin.scalacompat.{Block, Btc, MilliBtcDouble, OutPoint, SatoshiLong, Script, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{Block, Btc, MilliBtcDouble, OutPoint, SatoshiLong, Script, Transaction, TxId, TxOut} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse} import fr.acinq.eclair.blockchain.WatcherSpec._ import fr.acinq.eclair.blockchain.bitcoind.BitcoindService.SignTransactionResponse @@ -31,7 +32,7 @@ import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient.FundTransaction import fr.acinq.eclair.blockchain.bitcoind.zmq.ZMQActor import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.blockchain.{CurrentBlockHeight, NewTransaction} -import fr.acinq.eclair.{BlockHeight, RealShortChannelId, TestConstants, TestKitBaseClass, randomBytes32, randomKey} +import fr.acinq.eclair.{BlockHeight, RealShortChannelId, TestConstants, TestKitBaseClass, randomKey} import grizzled.slf4j.Logging import org.scalatest.BeforeAndAfterAll import org.scalatest.funsuite.AnyFunSuiteLike @@ -104,14 +105,14 @@ class ZmqWatcherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoind test("add/remove watches from/to utxo map") { val m0 = Map.empty[OutPoint, Set[Watch[_ <: WatchTriggered]]] - val txid = randomBytes32() + val txid = randomTxId() val outputIndex = 42 - val utxo = OutPoint(txid.reverse, outputIndex) + val utxo = OutPoint(txid, outputIndex) val w1 = WatchFundingSpent(TestProbe().ref, txid, outputIndex, hints = Set.empty) val w2 = WatchFundingSpent(TestProbe().ref, txid, outputIndex, hints = Set.empty) val w3 = WatchExternalChannelSpent(TestProbe().ref, txid, outputIndex, RealShortChannelId(1)) - val w4 = WatchExternalChannelSpent(TestProbe().ref, randomBytes32(), 5, RealShortChannelId(1)) + val w4 = WatchExternalChannelSpent(TestProbe().ref, randomTxId(), 5, RealShortChannelId(1)) val w5 = WatchFundingConfirmed(TestProbe().ref, txid, 3) // we test as if the collection was immutable @@ -122,17 +123,17 @@ class ZmqWatcherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoind val m3 = addWatchedUtxos(m2, w3) assert(m3.keySet == Set(utxo) && m3(utxo).size == 3) val m4 = addWatchedUtxos(m3, w4) - assert(m4.keySet == Set(utxo, OutPoint(w4.txId.reverse, w4.outputIndex)) && m3(utxo).size == 3) + assert(m4.keySet == Set(utxo, OutPoint(w4.txId, w4.outputIndex)) && m3(utxo).size == 3) val m5 = addWatchedUtxos(m4, w5) - assert(m5.keySet == Set(utxo, OutPoint(w4.txId.reverse, w4.outputIndex)) && m5(utxo).size == 3) + assert(m5.keySet == Set(utxo, OutPoint(w4.txId, w4.outputIndex)) && m5(utxo).size == 3) val m6 = removeWatchedUtxos(m5, w3) - assert(m6.keySet == Set(utxo, OutPoint(w4.txId.reverse, w4.outputIndex)) && m6(utxo).size == 2) + assert(m6.keySet == Set(utxo, OutPoint(w4.txId, w4.outputIndex)) && m6(utxo).size == 2) val m7 = removeWatchedUtxos(m6, w3) - assert(m7.keySet == Set(utxo, OutPoint(w4.txId.reverse, w4.outputIndex)) && m7(utxo).size == 2) + assert(m7.keySet == Set(utxo, OutPoint(w4.txId, w4.outputIndex)) && m7(utxo).size == 2) val m8 = removeWatchedUtxos(m7, w2) - assert(m8.keySet == Set(utxo, OutPoint(w4.txId.reverse, w4.outputIndex)) && m8(utxo).size == 1) + assert(m8.keySet == Set(utxo, OutPoint(w4.txId, w4.outputIndex)) && m8(utxo).size == 1) val m9 = removeWatchedUtxos(m8, w1) - assert(m9.keySet == Set(OutPoint(w4.txId.reverse, w4.outputIndex))) + assert(m9.keySet == Set(OutPoint(w4.txId, w4.outputIndex))) val m10 = removeWatchedUtxos(m9, w4) assert(m10.isEmpty) } @@ -281,7 +282,7 @@ class ZmqWatcherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoind watcher ! StopWatching(probe.ref) // We should still find tx2 if the provided hint is wrong - watcher ! WatchOutputSpent(probe.ref, tx1.txid, 0, Set(randomBytes32())) + watcher ! WatchOutputSpent(probe.ref, tx1.txid, 0, Set(randomTxId())) probe.fishForMessage() { case m: WatchOutputSpentTriggered => m.spendingTx.txid == tx2.txid } watcher ! StopWatching(probe.ref) @@ -359,11 +360,11 @@ class ZmqWatcherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoind val actor1 = TestProbe() val actor2 = TestProbe() - val txid = randomBytes32() + val txid = randomTxId() watcher ! WatchFundingConfirmed(actor1.ref, txid, 2) watcher ! WatchFundingConfirmed(actor1.ref, txid, 3) watcher ! WatchFundingDeeplyBuried(actor1.ref, txid, 3) - watcher ! WatchFundingConfirmed(actor1.ref, txid.reverse, 3) + watcher ! WatchFundingConfirmed(actor1.ref, TxId(txid.value.reverse), 3) watcher ! WatchOutputSpent(actor1.ref, txid, 0, Set.empty) watcher ! WatchOutputSpent(actor1.ref, txid, 1, Set.empty) watcher ! ListWatches(actor1.ref) @@ -372,7 +373,7 @@ class ZmqWatcherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoind watcher ! WatchFundingConfirmed(actor2.ref, txid, 2) watcher ! WatchFundingDeeplyBuried(actor2.ref, txid, 3) - watcher ! WatchFundingConfirmed(actor2.ref, txid.reverse, 3) + watcher ! WatchFundingConfirmed(actor2.ref, TxId(txid.value.reverse), 3) watcher ! WatchOutputSpent(actor2.ref, txid, 0, Set.empty) watcher ! WatchOutputSpent(actor2.ref, txid, 1, Set.empty) watcher ! ListWatches(actor2.ref) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala index fb0f5be56d..4ec9b9a026 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala @@ -18,6 +18,7 @@ package fr.acinq.eclair.channel import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, DeterministicWallet, Satoshi, SatoshiLong, Transaction} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee._ import fr.acinq.eclair.channel.Helpers.Funding @@ -30,7 +31,6 @@ import fr.acinq.eclair.wire.protocol.{IncorrectOrUnknownPaymentDetails, UpdateAd import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} -import java.util.concurrent.atomic.AtomicReference import scala.concurrent.duration._ import scala.util.Random @@ -489,9 +489,9 @@ object CommitmentsSpec { val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, Long.MaxValue.msat, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isInitiator, None, None, Features.empty) val remoteParams = RemoteParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) val remoteFundingPubKey = randomKey().publicKey - val commitmentInput = Funding.makeFundingInputInfo(randomBytes32(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) + val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil) - val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toRemote, toLocal), randomBytes32(), randomKey().publicKey) + val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toRemote, toLocal), randomTxId(), randomKey().publicKey) Commitments( ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), @@ -508,9 +508,9 @@ object CommitmentsSpec { val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, Long.MaxValue.msat, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, None, None, Features.empty) val remoteParams = RemoteParams(remoteNodeId, 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) val remoteFundingPubKey = randomKey().publicKey - val commitmentInput = Funding.makeFundingInputInfo(randomBytes32(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) + val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil) - val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toRemote, toLocal), randomBytes32(), randomKey().publicKey) + val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toRemote, toLocal), randomTxId(), randomKey().publicKey) Commitments( ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/HelpersSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/HelpersSpec.scala index cf63e02387..3203b581dd 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/HelpersSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/HelpersSpec.scala @@ -228,7 +228,7 @@ class HelpersSpec extends TestKitBaseClass with AnyFunSuiteLike with ChannelStat ) def toClosingTx(txOut: Seq[TxOut]): ClosingTx = { - ClosingTx(InputInfo(OutPoint(ByteVector32.Zeroes, 0), TxOut(1000 sat, Nil), Nil), Transaction(2, Nil, txOut, 0), None) + ClosingTx(InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 0), TxOut(1000 sat, Nil), Nil), Transaction(2, Nil, txOut, 0), None) } assert(Closing.MutualClose.checkClosingDustAmounts(toClosingTx(allOutputsAboveDust))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala index 6a6f779675..2573fa7d96 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala @@ -23,7 +23,8 @@ import akka.testkit.TestProbe import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt} import fr.acinq.bitcoin.psbt.Psbt import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, OP_1, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxOut, addressToPublicKeyScript} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, OP_1, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxHash, TxId, TxOut, addressToPublicKeyScript} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, ProcessPsbtResponse} import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient.{MempoolTx, Utxo} @@ -70,7 +71,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit txid <- client.publishTransaction(signed.finalTx_opt.toOption.get) } yield txid f.pipeTo(probe.ref) - probe.expectMsgType[ByteVector32] + probe.expectMsgType[TxId] } private def createInput(channelId: ByteVector32, serialId: UInt64, amount: Satoshi): TxAddInput = { @@ -105,7 +106,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val fundingPubkeyScript: ByteVector = Script.write(Script.pay2wsh(Scripts.multiSig2of2(fundingParamsB.remoteFundingPubKey, fundingParamsA.remoteFundingPubKey))) def dummySharedInputB(amount: Satoshi): SharedFundingInput = { - val inputInfo = InputInfo(OutPoint(randomBytes32(), 3), TxOut(amount, fundingPubkeyScript), Nil) + val inputInfo = InputInfo(OutPoint(randomTxId(), 3), TxOut(amount, fundingPubkeyScript), Nil) val fundingTxIndex = fundingParamsA.sharedInput_opt match { case Some(input: Multisig2of2Input) => input.fundingTxIndex + 1 case _ => 0 @@ -1034,7 +1035,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val Right(signedTx) = probe.expectMsgType[ProcessPsbtResponse].finalTx_opt assert(Transaction.write(signedTx).length >= 65_000) minerWallet.publishTransaction(signedTx).pipeTo(probe.ref) - probe.expectMsgType[ByteVector32] + probe.expectMsgType[TxId] } generateBlocks(1) @@ -1805,7 +1806,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val probe = TestProbe() walletB.getP2wpkhPubkey().pipeTo(probe.ref) walletB.sendToPubkeyScript(Script.write(Script.pay2wpkh(probe.expectMsgType[PublicKey])), 75_000 sat, FeeratePerKw(FeeratePerByte(1.sat))).pipeTo(probe.ref) - probe.expectMsgType[ByteVector32] + probe.expectMsgType[TxId] alice ! Start(alice2bob.ref) bob ! Start(bob2alice.ref) @@ -1841,7 +1842,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val probe = TestProbe() walletB.getReceiveAddress().pipeTo(probe.ref) walletB.sendToAddress(probe.expectMsgType[String], 75_000 sat, 1).pipeTo(probe.ref) - probe.expectMsgType[ByteVector32] + probe.expectMsgType[TxId] alice ! Start(alice2bob.ref) bob ! Start(bob2alice.ref) @@ -2335,7 +2336,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit bob ! Start(probe.ref) // Alice --- tx_add_input --> Bob // The input doesn't include the previous transaction but is not the shared input. - val nonSharedInput = TxAddInput(params.channelId, UInt64(0), OutPoint(randomBytes32(), 7), 0) + val nonSharedInput = TxAddInput(params.channelId, UInt64(0), OutPoint(randomTxId(), 7), 0) bob ! ReceiveMessage(nonSharedInput) assert(probe.expectMsgType[RemoteFailure].cause == PreviousTxMissing(params.channelId, UInt64(0))) } @@ -2438,7 +2439,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit probe.expectMsg(txA1.txId) // we modify remote's input in previous txs, it won't be double spent - val fakeTxB2 = txB1.modify(_.tx.remoteInputs.at(0).outPoint.hash).setTo(randomBytes32()) + val fakeTxB2 = txB1.modify(_.tx.remoteInputs.at(0).outPoint.hash).setTo(TxHash(randomBytes32())) val aliceRbf = fixtureParams.spawnTxBuilderRbfAlice(aliceParams.copy(targetFeerate = FeeratePerKw(10_000 sat)), commitmentA1, Seq(txA1), walletA) val bobRbf = fixtureParams.spawnTxBuilderRbfBob(bobParams.copy(targetFeerate = FeeratePerKw(10_000 sat)), commitmentB1, Seq(txB1, fakeTxB2), walletB) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/FinalTxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/FinalTxPublisherSpec.scala index fb4df104f1..8d8d59f9b8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/FinalTxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/FinalTxPublisherSpec.scala @@ -20,7 +20,7 @@ import akka.actor.typed.ActorRef import akka.actor.typed.scaladsl.adapter.{ClassicActorSystemOps, TypedActorRefOps, actorRefAdapter} import akka.pattern.pipe import akka.testkit.TestProbe -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Transaction} +import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Transaction, TxId} import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.blockchain.WatcherSpec.createSpendP2WPKH import fr.acinq.eclair.blockchain.bitcoind.BitcoindService @@ -63,7 +63,7 @@ class FinalTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bi probe.expectMsgType[Seq[Transaction]] } - def waitTxInMempool(bitcoinClient: BitcoinCoreClient, txId: ByteVector32, probe: TestProbe): Unit = { + def waitTxInMempool(bitcoinClient: BitcoinCoreClient, txId: TxId, probe: TestProbe): Unit = { awaitCond(getMempool(bitcoinClient, probe).exists(_.txid == txId)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitorSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitorSpec.scala index e3d9409788..36722db8be 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitorSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/MempoolTxMonitorSpec.scala @@ -21,7 +21,8 @@ import akka.actor.typed.scaladsl.adapter.{ClassicActorSystemOps, actorRefAdapter import akka.pattern.pipe import akka.testkit.TestProbe import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, SatoshiLong, Transaction, TxIn} +import fr.acinq.bitcoin.scalacompat.{OutPoint, SatoshiLong, Transaction, TxId, TxIn} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.WatcherSpec.{createSpendManyP2WPKH, createSpendP2WPKH} import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient @@ -29,7 +30,7 @@ import fr.acinq.eclair.channel.publish.MempoolTxMonitor._ import fr.acinq.eclair.channel.publish.TxPublisher.TxPublishContext import fr.acinq.eclair.channel.publish.TxPublisher.TxRejectedReason._ import fr.acinq.eclair.channel.{TransactionConfirmed, TransactionPublished} -import fr.acinq.eclair.{TestConstants, TestKitBaseClass, randomBytes32, randomKey} +import fr.acinq.eclair.{TestConstants, TestKitBaseClass, randomKey} import org.scalatest.BeforeAndAfterAll import org.scalatest.funsuite.AnyFunSuiteLike @@ -69,7 +70,7 @@ class MempoolTxMonitorSpec extends TestKitBaseClass with AnyFunSuiteLike with Bi probe.expectMsgType[Seq[Transaction]] } - def waitTxInMempool(bitcoinClient: BitcoinCoreClient, txId: ByteVector32, probe: TestProbe): Unit = { + def waitTxInMempool(bitcoinClient: BitcoinCoreClient, txId: TxId, probe: TestProbe): Unit = { awaitCond(getMempool(bitcoinClient, probe).exists(_.txid == txId)) } @@ -165,7 +166,7 @@ class MempoolTxMonitorSpec extends TestKitBaseClass with AnyFunSuiteLike with Bi import f._ val tx = createSpendP2WPKH(parentTx, priv, priv.publicKey, 5_000 sat, 0, 0) - val txUnknownInput = tx.copy(txIn = tx.txIn ++ Seq(TxIn(OutPoint(randomBytes32(), 13), Nil, 0))) + val txUnknownInput = tx.copy(txIn = tx.txIn ++ Seq(TxIn(OutPoint(randomTxId(), 13), Nil, 0))) monitor ! Publish(probe.ref, txUnknownInput, txUnknownInput.txIn.head.outPoint, "test-tx", 10 sat) probe.expectMsg(TxRejected(txUnknownInput.txid, InputGone)) } @@ -178,7 +179,7 @@ class MempoolTxMonitorSpec extends TestKitBaseClass with AnyFunSuiteLike with Bi generateBlocks(1) val tx = createSpendP2WPKH(parentTx, priv, priv.publicKey, 5_000 sat, 0, 0) - val txUnknownInput = tx.copy(txIn = tx.txIn ++ Seq(TxIn(OutPoint(randomBytes32(), 13), Nil, 0))) + val txUnknownInput = tx.copy(txIn = tx.txIn ++ Seq(TxIn(OutPoint(randomTxId(), 13), Nil, 0))) monitor ! Publish(probe.ref, txUnknownInput, txUnknownInput.txIn.head.outPoint, "test-tx", 10 sat) probe.expectMsg(TxRejected(txUnknownInput.txid, InputGone)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunderSpec.scala index e65a69e154..ff7591e67a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunderSpec.scala @@ -16,7 +16,8 @@ package fr.acinq.eclair.channel.publish -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, OutPoint, SatoshiLong, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, OutPoint, SatoshiLong, Script, Transaction, TxId, TxIn, TxOut} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel.Helpers.Funding import fr.acinq.eclair.channel.publish.ReplaceableTxFunder.AdjustPreviousTxOutputResult.{AddWalletInputs, TxOutputAdjusted} @@ -38,7 +39,7 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike { private def createAnchorTx(): (CommitTx, ClaimLocalAnchorOutputTx) = { val anchorScript = Scripts.anchor(PlaceHolderPubKey) - val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 1, 500 sat, PlaceHolderPubKey, PlaceHolderPubKey) + val commitInput = Funding.makeFundingInputInfo(randomTxId(), 1, 500 sat, PlaceHolderPubKey, PlaceHolderPubKey) val commitTx = Transaction( 2, Seq(TxIn(commitInput.outPoint, commitInput.redeemScript, 0, Scripts.witness2of2(PlaceHolderSig, PlaceHolderSig, PlaceHolderPubKey, PlaceHolderPubKey))), @@ -60,7 +61,7 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike { val htlcTimeoutScript = Scripts.htlcOffered(PlaceHolderPubKey, PlaceHolderPubKey, PlaceHolderPubKey, randomBytes32(), ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) val commitTx = Transaction( 2, - Seq(TxIn(OutPoint(randomBytes32(), 1), Script.write(Script.pay2wpkh(PlaceHolderPubKey)), 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig))), + Seq(TxIn(OutPoint(randomTxId(), 1), Script.write(Script.pay2wpkh(PlaceHolderPubKey)), 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig))), Seq(TxOut(5000 sat, Script.pay2wsh(htlcSuccessScript)), TxOut(4000 sat, Script.pay2wsh(htlcTimeoutScript))), 0 ) @@ -86,15 +87,15 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike { val htlcSuccessScript = Scripts.htlcReceived(PlaceHolderPubKey, PlaceHolderPubKey, PlaceHolderPubKey, paymentHash, CltvExpiry(0), ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) val htlcTimeoutScript = Scripts.htlcOffered(PlaceHolderPubKey, PlaceHolderPubKey, PlaceHolderPubKey, randomBytes32(), ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) val claimHtlcSuccess = ClaimHtlcSuccessWithWitnessData(ClaimHtlcSuccessTx( - InputInfo(OutPoint(ByteVector32.Zeroes, 3), TxOut(5000 sat, Script.pay2wsh(htlcSuccessScript)), htlcSuccessScript), - Transaction(2, Seq(TxIn(OutPoint(ByteVector32.Zeroes, 3), ByteVector.empty, 0)), Seq(TxOut(5000 sat, Script.pay2wpkh(PlaceHolderPubKey))), 0), + InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 3), TxOut(5000 sat, Script.pay2wsh(htlcSuccessScript)), htlcSuccessScript), + Transaction(2, Seq(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 3), ByteVector.empty, 0)), Seq(TxOut(5000 sat, Script.pay2wpkh(PlaceHolderPubKey))), 0), paymentHash, 5, ConfirmationTarget.Absolute(BlockHeight(0)) ), preimage) val claimHtlcTimeout = ClaimHtlcTimeoutWithWitnessData(ClaimHtlcTimeoutTx( - InputInfo(OutPoint(ByteVector32.Zeroes, 7), TxOut(5000 sat, Script.pay2wsh(htlcTimeoutScript)), htlcTimeoutScript), - Transaction(2, Seq(TxIn(OutPoint(ByteVector32.Zeroes, 7), ByteVector.empty, 0)), Seq(TxOut(5000 sat, Script.pay2wpkh(PlaceHolderPubKey))), 0), + InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 7), TxOut(5000 sat, Script.pay2wsh(htlcTimeoutScript)), htlcTimeoutScript), + Transaction(2, Seq(TxIn(OutPoint(TxId(ByteVector32.Zeroes), 7), ByteVector.empty, 0)), Seq(TxOut(5000 sat, Script.pay2wpkh(PlaceHolderPubKey))), 0), 7, ConfirmationTarget.Absolute(BlockHeight(0)) )) @@ -133,8 +134,8 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike { txIn = Seq( initialAnchorTx.tx.txIn.head, // The previous funding attempt added two wallet inputs: - TxIn(OutPoint(randomBytes32(), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), - TxIn(OutPoint(randomBytes32(), 1), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)) + TxIn(OutPoint(randomTxId(), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), + TxIn(OutPoint(randomTxId(), 1), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)) ), // And a change output: txOut = Seq(TxOut(5000 sat, Script.pay2wpkh(PlaceHolderPubKey))) @@ -173,9 +174,9 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike { txIn = Seq( initialHtlcTx.txInfo.tx.txIn.head, // The previous funding attempt added three wallet inputs: - TxIn(OutPoint(randomBytes32(), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), - TxIn(OutPoint(randomBytes32(), 1), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), - TxIn(OutPoint(randomBytes32(), 5), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)) + TxIn(OutPoint(randomTxId(), 3), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), + TxIn(OutPoint(randomTxId(), 1), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)), + TxIn(OutPoint(randomTxId(), 5), ByteVector.empty, 0, Script.witnessPay2wpkh(PlaceHolderPubKey, PlaceHolderSig)) ), txOut = Seq( initialHtlcTx.txInfo.tx.txOut.head, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala index 60b06dd0bf..de7327fa87 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala @@ -22,7 +22,7 @@ import akka.pattern.pipe import akka.testkit.{TestFSMRef, TestProbe} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, BtcAmount, ByteVector32, MilliBtcDouble, MnemonicCode, OutPoint, SatoshiLong, Transaction} +import fr.acinq.bitcoin.scalacompat.{Block, BtcAmount, MilliBtcDouble, MnemonicCode, OutPoint, SatoshiLong, Transaction, TxId} import fr.acinq.eclair.NotificationsLogger.NotifyNodeOperator import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ @@ -114,7 +114,7 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w }) } - def isInMempool(txid: ByteVector32): Boolean = { + def isInMempool(txid: TxId): Boolean = { getMempool().exists(_.txid == txid) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/TxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/TxPublisherSpec.scala index 7e6fa660c1..2e2cbf577d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/TxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/TxPublisherSpec.scala @@ -21,6 +21,7 @@ import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.adapter.{ClassicActorSystemOps, TypedActorRefOps, actorRefAdapter} import akka.testkit.TestProbe import fr.acinq.bitcoin.scalacompat.{OutPoint, SatoshiLong, Transaction, TxIn, TxOut} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.CurrentBlockHeight import fr.acinq.eclair.blockchain.fee.{ConfirmationPriority, ConfirmationTarget} import fr.acinq.eclair.channel.publish @@ -72,7 +73,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publish final tx") { f => import f._ - val tx = Transaction(2, TxIn(OutPoint(randomBytes32(), 1), Nil, 0) :: Nil, Nil, 0) + val tx = Transaction(2, TxIn(OutPoint(randomTxId(), 1), Nil, 0) :: Nil, Nil, 0) val cmd = PublishFinalTx(tx, tx.txIn.head.outPoint, "final-tx", 5 sat, None) txPublisher ! cmd val child = factory.expectMsgType[FinalTxPublisherSpawned].actor @@ -82,7 +83,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publish final tx duplicate") { f => import f._ - val input = OutPoint(randomBytes32(), 1) + val input = OutPoint(randomTxId(), 1) val tx1 = Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0) val cmd1 = PublishFinalTx(tx1, input, "final-tx", 10 sat, None) txPublisher ! cmd1 @@ -93,7 +94,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { factory.expectNoMessage(100 millis) // But a different tx spending the same main input is allowed: - val tx2 = tx1.copy(txIn = tx1.txIn ++ Seq(TxIn(OutPoint(randomBytes32(), 0), Nil, 0))) + val tx2 = tx1.copy(txIn = tx1.txIn ++ Seq(TxIn(OutPoint(randomTxId(), 0), Nil, 0))) val cmd2 = PublishFinalTx(tx2, input, "another-final-tx", 0 sat, None) txPublisher ! cmd2 factory.expectMsgType[FinalTxPublisherSpawned] @@ -103,7 +104,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { import f._ val confirmBefore = ConfirmationTarget.Absolute(nodeParams.currentBlockHeight + 12) - val input = OutPoint(randomBytes32(), 3) + val input = OutPoint(randomTxId(), 3) val cmd = PublishReplaceableTx(ClaimLocalAnchorOutputTx(InputInfo(input, TxOut(25_000 sat, Nil), Nil), Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0), confirmBefore), null) txPublisher ! cmd val child = factory.expectMsgType[ReplaceableTxPublisherSpawned].actor @@ -115,7 +116,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { import f._ val confirmBefore = nodeParams.currentBlockHeight + 12 - val input = OutPoint(randomBytes32(), 3) + val input = OutPoint(randomTxId(), 3) val anchorTx = ClaimLocalAnchorOutputTx(InputInfo(input, TxOut(25_000 sat, Nil), Nil), Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0), ConfirmationTarget.Priority(ConfirmationPriority.Medium)) val cmd = PublishReplaceableTx(anchorTx, null) txPublisher ! cmd @@ -161,14 +162,14 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("stop publishing attempts when transaction confirms") { f => import f._ - val input = OutPoint(randomBytes32(), 3) + val input = OutPoint(randomTxId(), 3) val tx1 = Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0) val cmd1 = PublishFinalTx(tx1, input, "final-tx-1", 5 sat, None) txPublisher ! cmd1 val attempt1 = factory.expectMsgType[FinalTxPublisherSpawned].actor attempt1.expectMsgType[FinalTxPublisher.Publish] - val tx2 = Transaction(2, TxIn(input, Nil, 0) :: TxIn(OutPoint(randomBytes32(), 0), Nil, 3) :: Nil, Nil, 0) + val tx2 = Transaction(2, TxIn(input, Nil, 0) :: TxIn(OutPoint(randomTxId(), 0), Nil, 3) :: Nil, Nil, 0) val cmd2 = PublishFinalTx(tx2, input, "final-tx-2", 15 sat, None) txPublisher ! cmd2 val attempt2 = factory.expectMsgType[FinalTxPublisherSpawned].actor @@ -189,7 +190,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (wallet input gone)") { f => import f._ - val input = OutPoint(randomBytes32(), 3) + val input = OutPoint(randomTxId(), 3) val tx1 = Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0) val cmd1 = PublishFinalTx(tx1, input, "final-tx-1", 0 sat, None) txPublisher ! cmd1 @@ -213,7 +214,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (main input gone)") { f => import f._ - val input = OutPoint(randomBytes32(), 3) + val input = OutPoint(randomTxId(), 3) val tx = Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0) val cmd = PublishFinalTx(tx, input, "final-tx", 0 sat, None) txPublisher ! cmd @@ -234,7 +235,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { import f._ val target = nodeParams.currentBlockHeight + 12 - val input = OutPoint(randomBytes32(), 7) + val input = OutPoint(randomTxId(), 7) val paymentHash = randomBytes32() val cmd = PublishReplaceableTx(HtlcSuccessTx(InputInfo(input, TxOut(25_000 sat, Nil), Nil), Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0), paymentHash, 3, ConfirmationTarget.Absolute(target)), null) txPublisher ! cmd @@ -254,13 +255,13 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (transaction skipped)") { f => import f._ - val tx1 = Transaction(2, TxIn(OutPoint(randomBytes32(), 1), Nil, 0) :: Nil, Nil, 0) + val tx1 = Transaction(2, TxIn(OutPoint(randomTxId(), 1), Nil, 0) :: Nil, Nil, 0) val cmd1 = PublishFinalTx(tx1, tx1.txIn.head.outPoint, "final-tx-1", 0 sat, None) txPublisher ! cmd1 val attempt1 = factory.expectMsgType[FinalTxPublisherSpawned] attempt1.actor.expectMsgType[FinalTxPublisher.Publish] - val tx2 = Transaction(2, TxIn(OutPoint(randomBytes32(), 0), Nil, 0) :: Nil, Nil, 0) + val tx2 = Transaction(2, TxIn(OutPoint(randomTxId(), 0), Nil, 0) :: Nil, Nil, 0) val cmd2 = PublishFinalTx(tx2, tx2.txIn.head.outPoint, "final-tx-2", 5 sat, None) txPublisher ! cmd2 val attempt2 = factory.expectMsgType[FinalTxPublisherSpawned] @@ -281,7 +282,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (unconfirmed conflicting raw transaction)") { f => import f._ - val tx = Transaction(2, TxIn(OutPoint(randomBytes32(), 1), Nil, 0) :: Nil, Nil, 0) + val tx = Transaction(2, TxIn(OutPoint(randomTxId(), 1), Nil, 0) :: Nil, Nil, 0) val cmd = PublishFinalTx(tx, tx.txIn.head.outPoint, "final-tx", 5 sat, None) txPublisher ! cmd val attempt = factory.expectMsgType[FinalTxPublisherSpawned] @@ -298,7 +299,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (unconfirmed conflicting replaceable transaction)") { f => import f._ - val input = OutPoint(randomBytes32(), 7) + val input = OutPoint(randomTxId(), 7) val paymentHash = randomBytes32() val cmd = PublishReplaceableTx(HtlcSuccessTx(InputInfo(input, TxOut(25_000 sat, Nil), Nil), Transaction(2, TxIn(input, Nil, 0) :: Nil, Nil, 0), paymentHash, 3, ConfirmationTarget.Absolute(nodeParams.currentBlockHeight)), null) txPublisher ! cmd @@ -318,7 +319,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (confirmed conflicting transaction)") { f => import f._ - val tx = Transaction(2, TxIn(OutPoint(randomBytes32(), 1), Nil, 0) :: Nil, Nil, 0) + val tx = Transaction(2, TxIn(OutPoint(randomTxId(), 1), Nil, 0) :: Nil, Nil, 0) val cmd = PublishFinalTx(tx, tx.txIn.head.outPoint, "final-tx", 5 sat, None) txPublisher ! cmd val attempt = factory.expectMsgType[FinalTxPublisherSpawned] @@ -335,7 +336,7 @@ class TxPublisherSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { test("publishing attempt fails (unknown failure)") { f => import f._ - val tx = Transaction(2, TxIn(OutPoint(randomBytes32(), 1), Nil, 0) :: Nil, Nil, 0) + val tx = Transaction(2, TxIn(OutPoint(randomTxId(), 1), Nil, 0) :: Nil, Nil, 0) val cmd = PublishFinalTx(tx, tx.txIn.head.outPoint, "final-tx", 5 sat, None) txPublisher ! cmd val attempt = factory.expectMsgType[FinalTxPublisherSpawned] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala index daf3595304..038892db9e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.channel.states.a import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, SatoshiLong} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel @@ -120,7 +120,7 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur test("recv OpenDualFundedChannel (invalid chain)", Tag(ChannelStateTestsTags.DualFunding), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val open = alice2bob.expectMsgType[OpenDualFundedChannel] - val chain = randomBytes32() + val chain = BlockHash(randomBytes32()) bob ! open.copy(chainHash = chain) val error = bob2alice.expectMsgType[Error] assert(error == Error(open.temporaryChannelId, InvalidChainHash(open.temporaryChannelId, Block.RegtestGenesisBlock.hash, chain).getMessage)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala index 62a6a152be..de8b70043f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala @@ -18,7 +18,8 @@ package fr.acinq.eclair.channel.states.b import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, SatoshiLong, TxId} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.SingleKeyOnChainWallet import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{WatchFundingConfirmed, WatchPublished} import fr.acinq.eclair.blockchain.fee.FeeratePerKw @@ -29,7 +30,7 @@ import fr.acinq.eclair.channel.publish.TxPublisher import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.io.Peer.OpenChannelResponse import fr.acinq.eclair.wire.protocol._ -import fr.acinq.eclair.{Features, MilliSatoshiLong, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion, randomBytes32} +import fr.acinq.eclair.{Features, MilliSatoshiLong, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -219,14 +220,14 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny val bobSigs = bob2alice.expectMsgType[TxSignatures] bob2blockchain.expectMsgType[WatchFundingConfirmed] - bob2alice.forward(alice, bobSigs.copy(txHash = randomBytes32(), witnesses = Nil)) + bob2alice.forward(alice, bobSigs.copy(txId = randomTxId(), witnesses = Nil)) alice2bob.expectMsgType[Error] awaitCond(wallet.rolledback.size == 1) aliceListener.expectMsgType[ChannelAborted] awaitCond(alice.stateName == CLOSED) // Bob has sent his signatures already, so he cannot close the channel yet. - alice2bob.forward(bob, TxSignatures(channelId(alice), randomBytes32(), Nil)) + alice2bob.forward(bob, TxSignatures(channelId(alice), randomTxId(), Nil)) bob2alice.expectMsgType[Error] bob2blockchain.expectNoMessage(100 millis) assert(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) @@ -390,7 +391,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny assert(listener.expectMsgType[TransactionPublished].tx.txid == fundingTxId) } - private def reconnect(f: FixtureParam, fundingTxId: ByteVector32): Unit = { + private def reconnect(f: FixtureParam, fundingTxId: TxId): Unit = { import f._ val listener = TestProbe() diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala index a78aa78959..5705a2a1d8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala @@ -653,10 +653,10 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 1 confirms alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) - alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx1.txid) + alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx1.txid) alice2bob.forward(bob) bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) - bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx1.txid) + bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx1.txid) bob2alice.forward(alice) alice2blockchain.expectWatchFundingSpent(fundingTx1.txid, Some(Set(fundingTx2.txid, commitAlice1.txid, commitBob1.txid))) bob2blockchain.expectWatchFundingSpent(fundingTx1.txid, Some(Set(fundingTx2.txid, commitAlice1.txid, commitBob1.txid))) @@ -665,10 +665,10 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 2 confirms alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) alice2bob.forward(bob) bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) bob2alice.forward(alice) alice2blockchain.expectWatchFundingSpent(fundingTx2.txid, Some(Set(commitAlice2.txid, commitBob2.txid))) bob2blockchain.expectWatchFundingSpent(fundingTx2.txid, Some(Set(commitAlice2.txid, commitBob2.txid))) @@ -689,9 +689,9 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik bob2blockchain.expectWatchFundingConfirmed(fundingTx1.txid) bob2blockchain.expectNoMessage(100 millis) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) alice2bob.forward(bob) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) bob2alice.forward(alice) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.size == 1) @@ -709,10 +709,10 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 2 confirms alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) alice2bob.forward(bob) bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) bob2alice.forward(alice) alice2blockchain.expectWatchFundingSpent(fundingTx2.txid, Some(Set(commitAlice2.txid, commitBob2.txid))) bob2blockchain.expectWatchFundingSpent(fundingTx2.txid, Some(Set(commitAlice2.txid, commitBob2.txid))) @@ -737,10 +737,10 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 1 confirms on alice, splice 2 confirms on bob alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) - alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx1.txid) + alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx1.txid) alice2bob.forward(bob) bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + bob2alice.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) bob2alice.forward(alice) alice2blockchain.expectWatchFundingSpent(fundingTx1.txid) bob2blockchain.expectWatchFundingSpent(fundingTx2.txid) @@ -751,7 +751,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 2 confirms on bob, splice 1 confirms on alice alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxid == fundingTx2.txid) + alice2bob.expectMsgTypeHaving[SpliceLocked](_.fundingTxId == fundingTx2.txid) alice2bob.forward(bob) bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) bob2alice.expectNoMessage(100 millis) @@ -1236,7 +1236,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik awaitCond(bob.stateData.asInstanceOf[DATA_NORMAL].spliceStatus == SpliceStatus.NoSplice) val spliceTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localFundingStatus.signedTx_opt.get alice ! WatchPublishedTriggered(spliceTx) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == spliceTxId) // Bob doesn't receive Alice's splice_locked + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == spliceTxId) // Bob doesn't receive Alice's splice_locked disconnect(f) val (channelReestablishAlice, channelReestablishBob) = reconnect(f, interceptFundingDeeplyBuried = false) @@ -1248,7 +1248,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik alice2bob.expectMsgType[TxSignatures] alice2bob.forward(bob) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == spliceTx.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == spliceTx.txid) alice2bob.forward(bob) bob2alice.expectNoMessage(100 millis) bob ! WatchFundingConfirmedTriggered(BlockHeight(42), 0, spliceTx) @@ -1343,58 +1343,58 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // splice 1 confirms on alice's side watchConfirmed1a.replyTo ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) alice2bob.forward(bob) alice2blockchain.expectMsgType[WatchFundingSpent] disconnect(f) reconnect(f) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) alice2bob.forward(bob) // splice 2 confirms on alice's side watchConfirmed2a.replyTo ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) alice2bob.forward(bob) alice2blockchain.expectMsgType[WatchFundingSpent] disconnect(f) reconnect(f) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) alice2bob.forward(bob) alice2bob.expectNoMessage(100 millis) bob2alice.expectNoMessage(100 millis) // splice 1 confirms on bob's side watchConfirmed1b.replyTo ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) bob2alice.forward(alice) bob2blockchain.expectMsgType[WatchFundingSpent] disconnect(f) reconnect(f) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) alice2bob.forward(bob) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx1.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx1.txid) bob2alice.forward(alice) alice2bob.expectNoMessage(100 millis) bob2alice.expectNoMessage(100 millis) // splice 2 confirms on bob's side watchConfirmed2b.replyTo ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx2) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) bob2blockchain.expectMsgType[WatchFundingSpent] // NB: we disconnect *before* transmitting the splice_confirmed to alice disconnect(f) reconnect(f) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) alice2bob.forward(bob) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) // this time alice received the splice_confirmed for funding tx 2 bob2alice.forward(alice) alice2bob.expectNoMessage(100 millis) @@ -1403,9 +1403,9 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik disconnect(f) reconnect(f) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) alice2bob.forward(bob) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxid == fundingTx2.txid) + assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx2.txid) bob2alice.forward(alice) alice2bob.expectNoMessage(100 millis) bob2alice.expectNoMessage(100 millis) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index 037782e285..d49bda0d51 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -3476,7 +3476,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice2blockchain.expectMsgType[WatchOutputSpent], // htlc 3 alice2blockchain.expectMsgType[WatchOutputSpent], // htlc 4 alice2blockchain.expectMsgType[WatchOutputSpent], // local anchor - ).map(w => OutPoint(w.txId.reverse, w.outputIndex)).toSet + ).map(w => OutPoint(w.txId, w.outputIndex)).toSet val localCommitPublished = alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.get assert(watchedOutputs == localCommitPublished.htlcTxs.keySet + localAnchor.txInfo.input.outPoint) alice2blockchain.expectNoMessage(1 second) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala index 3360ee233b..0f8fc3c752 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala @@ -21,6 +21,7 @@ import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, SatoshiLong, Script, Transaction, TxIn, TxOut} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ import fr.acinq.eclair.blockchain.fee.{ConfirmationPriority, ConfirmationTarget, FeeratePerKw, FeeratesPerKw} import fr.acinq.eclair.channel._ @@ -380,14 +381,14 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with channelUpdateListener.expectMsgType[LocalChannelDown] // scenario 1: bob claims the htlc output from the commit tx using its preimage - val claimHtlcSuccessFromCommitTx = Transaction(version = 0, txIn = TxIn(outPoint = OutPoint(randomBytes32(), 0), signatureScript = ByteVector.empty, sequence = 0, witness = Scripts.witnessClaimHtlcSuccessFromCommitTx(Transactions.PlaceHolderSig, ra1, ByteVector.fill(130)(33))) :: Nil, txOut = Nil, lockTime = 0) + val claimHtlcSuccessFromCommitTx = Transaction(version = 0, txIn = TxIn(outPoint = OutPoint(randomTxId(), 0), signatureScript = ByteVector.empty, sequence = 0, witness = Scripts.witnessClaimHtlcSuccessFromCommitTx(Transactions.PlaceHolderSig, ra1, ByteVector.fill(130)(33))) :: Nil, txOut = Nil, lockTime = 0) alice ! WatchOutputSpentTriggered(claimHtlcSuccessFromCommitTx) val fulfill1 = alice2relayer.expectMsgType[RES_ADD_SETTLED[Origin, HtlcResult.OnChainFulfill]] assert(fulfill1.htlc == htlca1) assert(fulfill1.result.paymentPreimage == ra1) // scenario 2: bob claims the htlc output from his own commit tx using its preimage (let's assume both parties had published their commitment tx) - val claimHtlcSuccessTx = Transaction(version = 0, txIn = TxIn(outPoint = OutPoint(randomBytes32(), 0), signatureScript = ByteVector.empty, sequence = 0, witness = Scripts.witnessHtlcSuccess(Transactions.PlaceHolderSig, Transactions.PlaceHolderSig, ra1, ByteVector.fill(130)(33), Transactions.DefaultCommitmentFormat)) :: Nil, txOut = Nil, lockTime = 0) + val claimHtlcSuccessTx = Transaction(version = 0, txIn = TxIn(outPoint = OutPoint(randomTxId(), 0), signatureScript = ByteVector.empty, sequence = 0, witness = Scripts.witnessHtlcSuccess(Transactions.PlaceHolderSig, Transactions.PlaceHolderSig, ra1, ByteVector.fill(130)(33), Transactions.DefaultCommitmentFormat)) :: Nil, txOut = Nil, lockTime = 0) alice ! WatchOutputSpentTriggered(claimHtlcSuccessTx) val fulfill2 = alice2relayer.expectMsgType[RES_ADD_SETTLED[Origin, HtlcResult.OnChainFulfill]] assert(fulfill2.htlc == htlca1) @@ -1584,7 +1585,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice2blockchain.expectNoMessage(1 second) // bob RBFs his htlc-success with a different transaction - val bobHtlcSuccessTx2 = bobHtlcSuccessTx1.tx.copy(txIn = TxIn(OutPoint(randomBytes32(), 0), Nil, 0) +: bobHtlcSuccessTx1.tx.txIn) + val bobHtlcSuccessTx2 = bobHtlcSuccessTx1.tx.copy(txIn = TxIn(OutPoint(randomTxId(), 0), Nil, 0) +: bobHtlcSuccessTx1.tx.txIn) assert(bobHtlcSuccessTx2.txid !== bobHtlcSuccessTx1.tx.txid) alice ! WatchOutputSpentTriggered(bobHtlcSuccessTx2) awaitCond(alice.stateData.asInstanceOf[DATA_CLOSING].revokedCommitPublished.head.claimHtlcDelayedPenaltyTxs.size == 3) @@ -1670,7 +1671,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val bobHtlcTx = Transaction( 2, Seq( - TxIn(OutPoint(randomBytes32(), 4), Nil, 1), // utxo used for fee bumping + TxIn(OutPoint(randomTxId(), 4), Nil, 1), // utxo used for fee bumping bobHtlcTxs(0).tx.txIn.head, bobHtlcTxs(1).tx.txIn.head, bobHtlcTxs(2).tx.txIn.head, @@ -1706,7 +1707,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice2blockchain.expectMsgType[WatchOutputSpent], alice2blockchain.expectMsgType[WatchOutputSpent], alice2blockchain.expectMsgType[WatchOutputSpent] - ).map(w => OutPoint(w.txId.reverse, w.outputIndex)).toSet + ).map(w => OutPoint(w.txId, w.outputIndex)).toSet assert(watchedOutpoints == spentOutpoints) alice2blockchain.expectNoMessage(1 second) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManagerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManagerSpec.scala index b550e452ea..9a4d4303f6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManagerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManagerSpec.scala @@ -21,7 +21,7 @@ class LocalOnChainKeyManagerSpec extends AnyFunSuite { Base64.getDecoder.decode("cHNidP8BAHECAAAAAfZo4nGIyTg77MFmEBkQH1Au3Jl8vzB2WWQGGz/MbyssAAAAAAD9////ArAHPgUAAAAAFgAU6j9yVvLg66Zu3GM/xHbmXT0yvyiAlpgAAAAAABYAFODscQh3N7lmDYyV5yrHpGL2Zd4JAAAAAAABAH0CAAAAAaNdmqUNlziIjSaif3JUcvJWdyF0U5bYq13NMe+LbaBZAAAAAAD9////AjSp1gUAAAAAFgAUjfFMfBg8ulo/874n3+0ode7ka0BAQg8AAAAAACIAIPUn/XU17DfnvDkj8gn2twG3jtr2Z7sthy9K2MPTdYkaAAAAAAEBHzSp1gUAAAAAFgAUjfFMfBg8ulo/874n3+0ode7ka0AiBgM+PDdyxsVisa66SyBxiUvhEam8lEP64yujvVsEcGaqIxgPCfOBVAAAgAEAAIAAAACAAQAAAAMAAAAAIgIDWmAhb/sCV9+HjwFpPuy2TyEBi/Y11wrEHZUihe3N80EYDwnzgVQAAIABAACAAAAAgAEAAAAFAAAAAAA=") ).getRight - val Success(psbt1) = onChainKeyManager.sign(psbt, psbt.getInputs.toArray().indices, Seq(0)) + val Success(psbt1) = onChainKeyManager.sign(psbt, psbt.inputs.toArray().indices, Seq(0)) val tx = psbt1.extract() assert(tx.isRight) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala index 4736d09bcd..1948d4f2e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.db import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Script, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, SatoshiLong, Script, Transaction, TxOut} import fr.acinq.eclair.TestDatabases.{TestPgDatabases, TestSqliteDatabases, migrationCheck} import fr.acinq.eclair._ import fr.acinq.eclair.channel.Helpers.Closing.MutualClose @@ -865,7 +865,7 @@ class AuditDbSpec extends AnyFunSuite { val channelId = randomBytes32() val scid = ShortChannelId(123) val remoteNodeId = randomKey().publicKey - val u = Announcements.makeChannelUpdate(randomBytes32(), randomKey(), remoteNodeId, scid, CltvExpiryDelta(56), 2000 msat, 1000 msat, 999, 1000000000 msat) + val u = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey(), remoteNodeId, scid, CltvExpiryDelta(56), 2000 msat, 1000 msat, 999, 1000000000 msat) dbs.audit.addChannelUpdate(ChannelUpdateParametersChanged(null, channelId, remoteNodeId, u)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/NetworkDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/NetworkDbSpec.scala index 5bc11f6096..59ac04db5f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/NetworkDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/NetworkDbSpec.scala @@ -17,10 +17,11 @@ package fr.acinq.eclair.db import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, TxId} import fr.acinq.eclair.FeatureSupport.Optional import fr.acinq.eclair.Features.VariableLengthOnion import fr.acinq.eclair.TestDatabases._ +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.db.jdbc.JdbcUtils.using import fr.acinq.eclair.db.pg.PgNetworkDb import fr.acinq.eclair.db.sqlite.SqliteNetworkDb @@ -86,7 +87,7 @@ class NetworkDbSpec extends AnyFunSuite { val db = dbs.network val sig = ByteVector64.Zeroes val c = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(42), randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, sig, sig, sig, sig) - val txid = ByteVector32.fromValidHex("0001" * 16) + val txid = TxId.fromValidHex("0001" * 16) db.addChannel(c, txid, Satoshi(42)) assert(db.listChannels() == SortedMap(c.shortChannelId -> PublicChannel(c, txid, Satoshi(42), None, None, None))) } @@ -112,9 +113,9 @@ class NetworkDbSpec extends AnyFunSuite { val channel_2 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(43), a.publicKey, c.publicKey, randomKey().publicKey, randomKey().publicKey, sig, sig, sig, sig) val channel_3 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(44), b.publicKey, c.publicKey, randomKey().publicKey, randomKey().publicKey, sig, sig, sig, sig) - val txid_1 = randomBytes32() - val txid_2 = randomBytes32() - val txid_3 = randomBytes32() + val txid_1 = randomTxId() + val txid_2 = randomTxId() + val txid_3 = randomTxId() val capacity = 10000 sat assert(db.listChannels().toSet == Set.empty) @@ -137,9 +138,9 @@ class NetworkDbSpec extends AnyFunSuite { channel_3.shortChannelId -> PublicChannel(channel_3, txid_3, capacity, None, None, None)) ) - val channel_update_1 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, a, b.publicKey, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) - val channel_update_2 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, b, a.publicKey, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) - val channel_update_3 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, b, c.publicKey, ShortChannelId(44), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) + val channel_update_1 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, a, b.publicKey, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, isPrivate = true) + val channel_update_2 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, b, a.publicKey, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, isPrivate = true) + val channel_update_3 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, b, c.publicKey, ShortChannelId(44), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, isPrivate = true) db.updateChannel(channel_update_1) db.updateChannel(channel_update_1) // duplicate is ignored @@ -214,9 +215,9 @@ class NetworkDbSpec extends AnyFunSuite { val capacity = 10000 sat val channels = shortChannelIds.map(id => Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, id, pub, pub, pub, pub, sig, sig, sig, sig)) - val template = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv, pub, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) + val template = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv, pub, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, isPrivate = true) val updates = shortChannelIds.map(id => template.copy(shortChannelId = id)) - val txid = randomBytes32() + val txid = randomTxId() channels.foreach(ca => db.addChannel(ca, txid, capacity)) updates.foreach(u => db.updateChannel(u)) assert(db.listChannels().keySet == channels.map(_.shortChannelId).toSet) @@ -391,7 +392,7 @@ object NetworkDbSpec { data: Array[Byte]) case class ChannelTestCase(shortChannelId: ShortChannelId, - txid: ByteVector32, + txid: TxId, channel: ChannelAnnouncement, channel_data: Array[Byte], capacity: Satoshi, @@ -425,7 +426,7 @@ object NetworkDbSpec { val channel_update_2_data = channel_update_2_opt.map(channelUpdateCodec.encode(_).require.toByteArray) ChannelTestCase( shortChannelId = channel.shortChannelId, - txid = randomBytes32(), + txid = randomTxId(), channel = channel, channel_data = channel_data, capacity = Random.nextInt(100_000).sat, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/PaymentsDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/PaymentsDbSpec.scala index 1eddf80102..7dc515d3fd 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/PaymentsDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/PaymentsDbSpec.scala @@ -793,7 +793,7 @@ class PaymentsDbSpec extends AnyFunSuite { object PaymentsDbSpec { val (alicePriv, bobPriv, carolPriv, davePriv) = (randomKey(), randomKey(), randomKey(), randomKey()) val (alice, bob, carol, dave) = (alicePriv.publicKey, bobPriv.publicKey, carolPriv.publicKey, davePriv.publicKey) - val hop_ab = ChannelHop(ShortChannelId(42), alice, bob, HopRelayParams.FromAnnouncement(ChannelUpdate(randomBytes64(), randomBytes32(), ShortChannelId(42), 1 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(12), 1 msat, 1 msat, 1, 500_000_000 msat))) + val hop_ab = ChannelHop(ShortChannelId(42), alice, bob, HopRelayParams.FromAnnouncement(ChannelUpdate(randomBytes64(), Block.RegtestGenesisBlock.hash, ShortChannelId(42), 1 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(12), 1 msat, 1 msat, 1, 500_000_000 msat))) val hop_bc = NodeHop(bob, carol, CltvExpiryDelta(14), 1 msat) val (preimage1, preimage2, preimage3, preimage4) = (randomBytes32(), randomBytes32(), randomBytes32(), randomBytes32()) val (paymentHash1, paymentHash2, paymentHash3, paymentHash4) = (Crypto.sha256(preimage1), Crypto.sha256(preimage2), Crypto.sha256(preimage3), Crypto.sha256(preimage4)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala index a4ffde4a09..f7985710f1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala @@ -23,7 +23,7 @@ import akka.testkit.TestProbe import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, BtcDouble, ByteVector32, Crypto, OutPoint, SatoshiLong, Script, Transaction, computeBIP84Address} +import fr.acinq.bitcoin.scalacompat.{Block, BtcDouble, ByteVector32, Crypto, OutPoint, SatoshiLong, Script, Transaction, TxId, computeBIP84Address} import fr.acinq.eclair.blockchain.bitcoind.BitcoindService.BitcoinReq import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient import fr.acinq.eclair.channel._ @@ -70,7 +70,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec { } /** Wait for the given transaction to be either in the mempool or confirmed. */ - def waitForTxBroadcastOrConfirmed(txid: ByteVector32, bitcoinClient: BitcoinCoreClient, sender: TestProbe): Unit = { + def waitForTxBroadcastOrConfirmed(txid: TxId, bitcoinClient: BitcoinCoreClient, sender: TestProbe): Unit = { awaitCond({ bitcoinClient.getMempool().pipeTo(sender.ref) val inMempool = sender.expectMsgType[Seq[Transaction]].exists(_.txid == txid) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala index 76c642cc1f..accf5fc6b5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala @@ -8,7 +8,7 @@ import akka.testkit.{TestActor, TestProbe} import com.softwaremill.quicklens.ModifyPimp import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi, SatoshiLong, Transaction} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi, SatoshiLong, Transaction, TxId} import fr.acinq.eclair.ShortChannelId.txIndex import fr.acinq.eclair.blockchain.DummyOnChainWallet import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher @@ -273,9 +273,9 @@ object MinimalNodeFixture extends Assertions with Eventually with IntegrationPat * Computes a deterministic [[RealShortChannelId]] based on a txid. We need this so that watchers can verify * transactions in a independent and stateless fashion, since there is no actual blockchain in those tests. */ - def deterministicShortId(txId: ByteVector32): RealShortChannelId = { - val blockHeight = txId.take(3).toInt(signed = false) - val txIndex = txId.takeRight(2).toInt(signed = false) + def deterministicShortId(txId: TxId): RealShortChannelId = { + val blockHeight = txId.value.take(3).toInt(signed = false) + val txIndex = txId.value.takeRight(2).toInt(signed = false) val outputIndex = 0 // funding txs created by the dummy wallet used in tests only have one output RealShortChannelId(BlockHeight(blockHeight), txIndex, outputIndex) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala index be351aa5da..4647913fa2 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala @@ -20,7 +20,7 @@ import akka.actor.testkit.typed.scaladsl.{ScalaTestWithActorTestKit, TestProbe} import akka.actor.typed.eventstream.EventStream.Publish import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Transaction, TxId, TxOut} import fr.acinq.eclair.channel._ import fr.acinq.eclair.io.PendingChannelsRateLimiter.filterPendingChannels import fr.acinq.eclair.router.Router @@ -74,11 +74,11 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac val tx = Transaction.read("010000000110f01d4a4228ef959681feb1465c2010d0135be88fd598135b2e09d5413bf6f1000000006a473044022074658623424cebdac8290488b76f893cfb17765b7a3805e773e6770b7b17200102202892cfa9dda662d5eac394ba36fcfd1ea6c0b8bb3230ab96220731967bbdb90101210372d437866d9e4ead3d362b01b615d24cc0d5152c740d51e3c55fb53f6d335d82ffffffff01408b0700000000001976a914678db9a7caa2aca887af1177eda6f3d0f702df0d88ac00000000") val closingTx = ClosingTx(InputInfo(tx.txIn.head.outPoint, TxOut(10_000 sat, Nil), Nil), tx, None) val channelsOnWhitelistAtLimit: Seq[PersistentChannelData] = Seq( - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerOnWhitelistAtLimit, randomBytes32()), BlockHeight(0), None, Left(FundingCreated(randomBytes32(), ByteVector32.Zeroes, 3, randomBytes64()))), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerOnWhitelistAtLimit, randomBytes32()), BlockHeight(0), None, Left(FundingCreated(randomBytes32(), TxId(ByteVector32.Zeroes), 3, randomBytes64()))), DATA_WAIT_FOR_CHANNEL_READY(commitments(peerOnWhitelistAtLimit, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), ) val channelsAtLimit1 = Seq( - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerAtLimit1, channelIdAtLimit1), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, ByteVector32.Zeroes, 3, randomBytes64()))), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerAtLimit1, channelIdAtLimit1), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, TxId(ByteVector32.Zeroes), 3, randomBytes64()))), DATA_WAIT_FOR_CHANNEL_READY(commitments(peerAtLimit1, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), ) val channelsAtLimit2 = Seq( @@ -86,7 +86,7 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(peerAtLimit2, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), ) val channelsBelowLimit1 = Seq( - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, channelIdBelowLimit1), BlockHeight(0), None, Left(FundingCreated(channelIdBelowLimit1, ByteVector32.Zeroes, 3, randomBytes64()))), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, channelIdBelowLimit1), BlockHeight(0), None, Left(FundingCreated(channelIdBelowLimit1, TxId(ByteVector32.Zeroes), 3, randomBytes64()))), ) val channelsBelowLimit2 = Seq( DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(peerBelowLimit2, channelIdBelowLimit2), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), @@ -99,7 +99,7 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac DATA_NORMAL(commitments(privatePeer2, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None), None, null, None, None, None, SpliceStatus.NoSplice), ) val initiatorChannels = Seq( - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, randomBytes32(), isInitiator = true), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, ByteVector32.Zeroes, 3, randomBytes64()))), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, randomBytes32(), isInitiator = true), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, TxId(ByteVector32.Zeroes), 3, randomBytes64()))), DATA_WAIT_FOR_CHANNEL_READY(commitments(peerBelowLimit1, randomBytes32(), isInitiator = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments(peerAtLimit1, randomBytes32(), isInitiator = true), 0 msat, 0 msat, BlockHeight(0), BlockHeight(0), RbfStatus.NoRbf, None), DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(peerAtLimit1, randomBytes32(), isInitiator = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), @@ -319,7 +319,7 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(randomKey().publicKey, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), DATA_NORMAL(commitments(randomKey().publicKey, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None), None, null, None, None, None, SpliceStatus.NoSplice), DATA_SHUTDOWN(commitments(randomKey().publicKey, randomBytes32()), Shutdown(randomBytes32(), ByteVector.empty), Shutdown(randomBytes32(), ByteVector.empty), None), - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(randomKey().publicKey, randomBytes32()), BlockHeight(0), None, Left(FundingCreated(randomBytes32(), ByteVector32.Zeroes, 3, randomBytes64()))), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(randomKey().publicKey, randomBytes32()), BlockHeight(0), None, Left(FundingCreated(randomBytes32(), TxId(ByteVector32.Zeroes), 3, randomBytes64()))), ) val limiter = testKit.spawn(PendingChannelsRateLimiter(nodeParams, router.ref, channels)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala index d85d26e696..90ff1ecde8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.json import akka.actor.ActorRef import akka.testkit.TestProbe import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, Btc, ByteVector32, ByteVector64, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Transaction, TxOut} +import fr.acinq.bitcoin.scalacompat.{Block, Btc, ByteVector32, ByteVector64, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Transaction, TxHash, TxId, TxOut} import fr.acinq.eclair._ import fr.acinq.eclair.balance.CheckBalance import fr.acinq.eclair.balance.CheckBalance.{ClosingBalance, GlobalBalance, MainAndHtlcBalance, PossiblyPublishedMainAndHtlcBalance, PossiblyPublishedMainBalance} @@ -44,8 +44,8 @@ import java.util.UUID class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Matchers { test("deserialize Map[OutPoint, ByteVector]") { - val output1 = OutPoint(ByteVector32(hex"11418a2d282a40461966e4f578e1fdf633ad15c1b7fb3e771d14361127233be1"), 0) - val output2 = OutPoint(ByteVector32(hex"3d62bd4f71dc63798418e59efbc7532380c900b5e79db3a5521374b161dd0e33"), 1) + val output1 = OutPoint(TxHash.fromValidHex("11418a2d282a40461966e4f578e1fdf633ad15c1b7fb3e771d14361127233be1"), 0) + val output2 = OutPoint(TxHash.fromValidHex("3d62bd4f71dc63798418e59efbc7532380c900b5e79db3a5521374b161dd0e33"), 1) val map = Map( output1 -> hex"dead", output2 -> hex"beef" @@ -63,8 +63,8 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat } test("deserialize Map[OutPoint, Transaction]") { - val output1 = OutPoint(ByteVector32(hex"11418a2d282a40461966e4f578e1fdf633ad15c1b7fb3e771d14361127233be1"), 0) - val output2 = OutPoint(ByteVector32(hex"3d62bd4f71dc63798418e59efbc7532380c900b5e79db3a5521374b161dd0e33"), 1) + val output1 = OutPoint(TxHash.fromValidHex("11418a2d282a40461966e4f578e1fdf633ad15c1b7fb3e771d14361127233be1"), 0) + val output2 = OutPoint(TxHash.fromValidHex("3d62bd4f71dc63798418e59efbc7532380c900b5e79db3a5521374b161dd0e33"), 1) val map = Map( output1 -> Transaction.read("0200000001c8a8934fb38a44b969528252bc37be66ee166c7897c57384d1e561449e110c93010000006b483045022100dc6c50f445ed53d2fb41067fdcb25686fe79492d90e6e5db43235726ace247210220773d35228af0800c257970bee9cf75175d75217de09a8ecd83521befd040c4ca012102082b751372fe7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247ba2300000000001976a914f97a7641228e6b17d4b0b08252ae75bd62a95fe788ace3de24000000000017a914a9fefd4b9a9282a1d7a17d2f14ac7d1eb88141d287f7d50800"), output2 -> Transaction.read("0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000") @@ -121,9 +121,9 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat val dummyBytes32 = ByteVector32(hex"0202020202020202020202020202020202020202020202020202020202020202") val localParams = LocalParams(dummyPublicKey, DeterministicWallet.KeyPath(Seq(42L)), 546 sat, Long.MaxValue.msat, Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, None, None, Features.empty) val remoteParams = RemoteParams(dummyPublicKey, 546 sat, UInt64.MaxValue, Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, dummyPublicKey, dummyPublicKey, dummyPublicKey, dummyPublicKey, Features.empty, None) - val commitmentInput = Funding.makeFundingInputInfo(dummyBytes32, 0, 150_000 sat, dummyPublicKey, dummyPublicKey) + val commitmentInput = Funding.makeFundingInputInfo(TxId(dummyBytes32), 0, 150_000 sat, dummyPublicKey, dummyPublicKey) val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 100_000_000 msat, 50_000_000 msat), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil) - val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 50_000_000 msat, 100_000_000 msat), dummyBytes32, dummyPublicKey) + val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 50_000_000 msat, 100_000_000 msat), TxId(dummyBytes32), dummyPublicKey) val channelInfo = RES_GET_CHANNEL_INFO( PublicKey(hex"0270685ca81a8e4d4d01beec5781f4cc924684072ae52c507f8ebe9daf0caaab7b"), ByteVector32(hex"345b2b05ec046ffe0c14d3b61838c79980713ad1cf8ae7a45c172ce90c9c0b9f"), @@ -276,7 +276,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat test("InputInfo serialization") { val inputInfo = InputInfo( - outPoint = OutPoint(ByteVector32(hex"345b2b05ec046ffe0c14d3b61838c79980713ad1cf8ae7a45c172ce90c9c0b9f"), 42), + outPoint = OutPoint(TxHash.fromValidHex("345b2b05ec046ffe0c14d3b61838c79980713ad1cf8ae7a45c172ce90c9c0b9f"), 42), txOut = TxOut(456651 sat, hex"3c7a66997c681a3de1bae56438abeee4fc50a16554725a430ade1dc8db6bdd76704d45c6151c4051d710cf487e63"), redeemScript = hex"00dc6c50f445ed53d2fb41067fdcb25686fe79492d90e6e5db43235726ace247210220773" ) @@ -331,11 +331,11 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat htlcs = Btc(0.05) ), closing = ClosingBalance( localCloseBalance = PossiblyPublishedMainAndHtlcBalance( - toLocal = Map(ByteVector32(hex"4d176ad844c363bed59edf81962b008faa6194c3b3757ffcd26ba60f95716db2") -> Btc(0.1)), - htlcs = Map(ByteVector32(hex"94b70cec5a98d67d17c6e3de5c7697f8a6cab4f698df91e633ce35efa3574d71") -> Btc(0.03), ByteVector32(hex"a844edd41ce8503864f3c95d89d850b177a09d7d35e950a7d27c14abb63adb13") -> Btc(0.06)), + toLocal = Map(TxId.fromValidHex("4d176ad844c363bed59edf81962b008faa6194c3b3757ffcd26ba60f95716db2") -> Btc(0.1)), + htlcs = Map(TxId.fromValidHex("94b70cec5a98d67d17c6e3de5c7697f8a6cab4f698df91e633ce35efa3574d71") -> Btc(0.03), TxId.fromValidHex("a844edd41ce8503864f3c95d89d850b177a09d7d35e950a7d27c14abb63adb13") -> Btc(0.06)), htlcsUnpublished = Btc(0.01)), mutualCloseBalance = PossiblyPublishedMainBalance( - toLocal = Map(ByteVector32(hex"7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247") -> Btc(0.1))) + toLocal = Map(TxId.fromValidHex("7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247") -> Btc(0.1))) )) ) JsonSerializers.serialization.write(gb)(JsonSerializers.formats) shouldBe """{"total":1.0,"onChain":{"confirmed":0.4,"unconfirmed":0.05},"offChain":{"waitForFundingConfirmed":0.0,"waitForChannelReady":0.0,"normal":{"toLocal":0.2,"htlcs":0.05},"shutdown":{"toLocal":0.0,"htlcs":0.0},"negotiating":0.0,"closing":{"localCloseBalance":{"toLocal":{"4d176ad844c363bed59edf81962b008faa6194c3b3757ffcd26ba60f95716db2":0.1},"htlcs":{"94b70cec5a98d67d17c6e3de5c7697f8a6cab4f698df91e633ce35efa3574d71":0.03,"a844edd41ce8503864f3c95d89d850b177a09d7d35e950a7d27c14abb63adb13":0.06},"htlcsUnpublished":0.01},"remoteCloseBalance":{"toLocal":{},"htlcs":{},"htlcsUnpublished":0.0},"mutualCloseBalance":{"toLocal":{"7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247":0.1}},"unknownCloseBalance":{"toLocal":0.0,"htlcs":0.0}},"waitForPublishFutureCommitment":0.0}}""" @@ -353,13 +353,13 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat test("TransactionWithInputInfo serializer") { // the input info is ignored when serializing to JSON - val dummyInputInfo = InputInfo(OutPoint(ByteVector32.Zeroes, 0), TxOut(Satoshi(0), Nil), Nil) + val dummyInputInfo = InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 0), TxOut(Satoshi(0), Nil), Nil) val htlcSuccessTx = Transaction.read("0200000001c8a8934fb38a44b969528252bc37be66ee166c7897c57384d1e561449e110c93010000006b483045022100dc6c50f445ed53d2fb41067fdcb25686fe79492d90e6e5db43235726ace247210220773d35228af0800c257970bee9cf75175d75217de09a8ecd83521befd040c4ca012102082b751372fe7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247ba2300000000001976a914f97a7641228e6b17d4b0b08252ae75bd62a95fe788ace3de24000000000017a914a9fefd4b9a9282a1d7a17d2f14ac7d1eb88141d287f7d50800") val htlcSuccessTxInfo = HtlcSuccessTx(dummyInputInfo, htlcSuccessTx, ByteVector32.One, 3, ConfirmationTarget.Absolute(BlockHeight(1105))) val htlcSuccessJson = s"""{ - | "txid": "${htlcSuccessTx.txid.toHex}", + | "txid": "${htlcSuccessTx.txid.value.toHex}", | "tx": "0200000001c8a8934fb38a44b969528252bc37be66ee166c7897c57384d1e561449e110c93010000006b483045022100dc6c50f445ed53d2fb41067fdcb25686fe79492d90e6e5db43235726ace247210220773d35228af0800c257970bee9cf75175d75217de09a8ecd83521befd040c4ca012102082b751372fe7e3b012534afe0bb8d1f2f09c724b1a10a813ce704e5b9c217ccfdffffff0247ba2300000000001976a914f97a7641228e6b17d4b0b08252ae75bd62a95fe788ace3de24000000000017a914a9fefd4b9a9282a1d7a17d2f14ac7d1eb88141d287f7d50800", | "paymentHash": "0100000000000000000000000000000000000000000000000000000000000000", | "htlcId": 3, @@ -372,7 +372,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat val claimHtlcTimeoutTxInfo = ClaimHtlcTimeoutTx(dummyInputInfo, claimHtlcTimeoutTx, 2, ConfirmationTarget.Absolute(BlockHeight(144))) val claimHtlcTimeoutJson = s"""{ - | "txid": "${claimHtlcTimeoutTx.txid.toHex}", + | "txid": "${claimHtlcTimeoutTx.txid.value.toHex}", | "tx": "010000000110f01d4a4228ef959681feb1465c2010d0135be88fd598135b2e09d5413bf6f1000000006a473044022074658623424cebdac8290488b76f893cfb17765b7a3805e773e6770b7b17200102202892cfa9dda662d5eac394ba36fcfd1ea6c0b8bb3230ab96220731967bbdb90101210372d437866d9e4ead3d362b01b615d24cc0d5152c740d51e3c55fb53f6d335d82ffffffff01408b0700000000001976a914678db9a7caa2aca887af1177eda6f3d0f702df0d88ac00000000", | "htlcId": 2, | "confirmBeforeBlock": 144 @@ -384,7 +384,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat val closingTxWithLocalOutput = ClosingTx(dummyInputInfo, closingTx, Some(OutputInfo(1, Satoshi(15000), hex"deadbeef"))) val closingTxWithLocalOutputJson = s"""{ - | "txid": "${closingTx.txid.toHex}", + | "txid": "${closingTx.txid.value.toHex}", | "tx": "0100000001be43e9788523ed4de0b24a007a90009bc25e667ddac0e9ee83049be03e220138000000006b483045022100f74dd6ad3e6a00201d266a0ed860a6379c6e68b473970423f3fc8a15caa1ea0f022065b4852c9da230d9e036df743cb743601ca5229e1cb610efdd99769513f2a2260121020636de7755830fb4a3f136e97ecc6c58941611957ba0364f01beae164b945b2fffffffff0150f80c000000000017a9146809053148799a10480eada3d56d15edf4a648c88700000000", | "toLocalOutput": { | "index": 1, @@ -398,7 +398,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat val closingTxWithoutLocalOutput = ClosingTx(dummyInputInfo, closingTx, None) val closingTxWithoutLocalOutputJson = s"""{ - | "txid": "${closingTx.txid.toHex}", + | "txid": "${closingTx.txid.value.toHex}", | "tx": "0100000001be43e9788523ed4de0b24a007a90009bc25e667ddac0e9ee83049be03e220138000000006b483045022100f74dd6ad3e6a00201d266a0ed860a6379c6e68b473970423f3fc8a15caa1ea0f022065b4852c9da230d9e036df743cb743601ca5229e1cb610efdd99769513f2a2260121020636de7755830fb4a3f136e97ecc6c58941611957ba0364f01beae164b945b2fffffffff0150f80c000000000017a9146809053148799a10480eada3d56d15edf4a648c88700000000" |} """.stripMargin diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala index bcd9777caf..48d2feb33e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.payment import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, BtcDouble, ByteVector32, Crypto, MilliBtcDouble, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BtcDouble, ByteVector32, Crypto, MilliBtcDouble, SatoshiLong} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features.{PaymentMetadata, PaymentSecret, _} import fr.acinq.eclair.payment.Bolt11Invoice._ @@ -43,7 +43,7 @@ class Bolt11InvoiceSpec extends AnyFunSuite { assert(nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) // Copy of Bolt11Invoice.apply that doesn't strip unknown features - def createInvoiceUnsafe(chainHash: ByteVector32, + def createInvoiceUnsafe(chainHash: BlockHash, amount: Option[MilliSatoshi], paymentHash: ByteVector32, privateKey: PrivateKey, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt12InvoiceSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt12InvoiceSpec.scala index b9538c7ab5..537b5a9ba1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt12InvoiceSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt12InvoiceSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.payment import fr.acinq.bitcoin.Bech32 import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features.{BasicMultiPartPayment, VariableLengthOnion} import fr.acinq.eclair.crypto.Sphinx @@ -55,7 +55,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { } test("check invoice signature") { - val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), randomBytes32()) + val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), BlockHash(randomBytes32())) val offer = Offer(Some(10000 msat), "test offer", nodeKey.publicKey, Features.empty, chain) val request = InvoiceRequest(offer, 11000 msat, 1, Features.empty, payerKey, chain) val invoice = Bolt12Invoice(request, randomBytes32(), nodeKey, 300 seconds, Features.empty, Seq(createPaymentBlindedRoute(nodeKey.publicKey))) @@ -72,7 +72,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { } test("check invoice signature with unknown field from invoice request") { - val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), randomBytes32()) + val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), BlockHash(randomBytes32())) val offer = Offer(Some(10000 msat), "test offer", nodeKey.publicKey, Features.empty, chain) val basicRequest = InvoiceRequest(offer, 11000 msat, 1, Features.empty, payerKey, chain) val requestWithUnknownTlv = basicRequest.copy(records = TlvStream(basicRequest.records.records, Set(GenericTlv(UInt64(87), hex"0404")))) @@ -83,7 +83,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { } test("check that invoice matches offer") { - val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), randomBytes32()) + val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), BlockHash(randomBytes32())) val offer = Offer(Some(10000 msat), "test offer", nodeKey.publicKey, Features.empty, chain) val request = InvoiceRequest(offer, 11000 msat, 1, Features.empty, payerKey, chain) val invoice = Bolt12Invoice(request, randomBytes32(), nodeKey, 300 seconds, Features.empty, Seq(createPaymentBlindedRoute(nodeKey.publicKey))) @@ -104,7 +104,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { } test("check that invoice matches invoice request") { - val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), randomBytes32()) + val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), BlockHash(randomBytes32())) val offer = Offer(Some(15000 msat), "test offer", nodeKey.publicKey, Features.empty, chain) val request = InvoiceRequest(offer, 15000 msat, 1, Features.empty, payerKey, chain) assert(request.quantity_opt.isEmpty) // when paying for a single item, the quantity field must not be present @@ -145,7 +145,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { } test("check invoice expiry") { - val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), randomBytes32()) + val (nodeKey, payerKey, chain) = (randomKey(), randomKey(), BlockHash(randomBytes32())) val offer = Offer(Some(5000 msat), "test offer", nodeKey.publicKey, Features.empty, chain) val request = InvoiceRequest(offer, 5000 msat, 1, Features.empty, payerKey, chain) val invoice = Bolt12Invoice(request, randomBytes32(), nodeKey, 300 seconds, Features.empty, Seq(createPaymentBlindedRoute(nodeKey.publicKey))) @@ -251,7 +251,7 @@ class Bolt12InvoiceSpec extends AnyFunSuite { assert(codedDecoded.paymentHash == paymentHash) assert(codedDecoded.relativeExpiry == relativeExpiry.seconds) assert(codedDecoded.fallbacks.contains(fallbacks)) - assert(codedDecoded.records.unknown.toSet == Set(GenericTlv(UInt64(121), hex"010203"), GenericTlv(UInt64(313), hex"baba"))) + assert(codedDecoded.records.unknown == Set(GenericTlv(UInt64(121), hex"010203"), GenericTlv(UInt64(313), hex"baba"))) } test("minimal tip") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala index 128b360929..88515aadd8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala @@ -21,6 +21,7 @@ import fr.acinq.bitcoin.scalacompat.DeterministicWallet.ExtendedPrivateKey import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, TxOut} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features._ +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.crypto.{ShaChain, Sphinx} @@ -704,7 +705,7 @@ object PaymentPacketSpec { val channelReserve = testCapacity * 0.01 val localParams = LocalParams(null, null, null, Long.MaxValue.msat, Some(channelReserve), null, null, 0, isInitiator = true, None, None, null) val remoteParams = RemoteParams(randomKey().publicKey, null, UInt64.MaxValue, Some(channelReserve), null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, None) - val commitInput = InputInfo(OutPoint(randomBytes32(), 1), TxOut(testCapacity, Nil), Nil) + val commitInput = InputInfo(OutPoint(randomTxId(), 1), TxOut(testCapacity, Nil), Nil) val localCommit = LocalCommit(0, null, CommitTxAndRemoteSig(Transactions.CommitTx(commitInput, null), null), Nil) val remoteCommit = RemoteCommit(0, null, null, randomKey().publicKey) val localChanges = LocalChanges(Nil, Nil, Nil) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala index 5e3d622ddb..5917e752f4 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.router -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, SatoshiLong, TxId} import fr.acinq.eclair.RealShortChannelId import fr.acinq.eclair.router.Router.{ChannelMeta, PublicChannel} import fr.acinq.eclair.router.Sync._ @@ -103,8 +103,8 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { val ef = RouteCalculationSpec.makeChannel(167514L, e, f) val channels = SortedMap( - ab.shortChannelId -> PublicChannel(ab, ByteVector32.Zeroes, 0 sat, Some(uab1), Some(uab2), Some(ChannelMeta(1000 msat, 400 msat))), - cd.shortChannelId -> PublicChannel(cd, ByteVector32.Zeroes, 0 sat, Some(ucd1), None, None) + ab.shortChannelId -> PublicChannel(ab, TxId(ByteVector32.Zeroes), 0 sat, Some(uab1), Some(uab2), Some(ChannelMeta(1000 msat, 400 msat))), + cd.shortChannelId -> PublicChannel(cd, TxId(ByteVector32.Zeroes), 0 sat, Some(ucd1), None, None) ) assert(getChannelDigestInfo(channels)(ab.shortChannelId) == (Timestamps(now, now), Checksums(3352963162L, 2581904122L))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala index 81cfc6c036..edec7c97a9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.router import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Satoshi, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Satoshi, SatoshiLong, TxId} import fr.acinq.eclair.payment.relay.Relayer.RelayFees import fr.acinq.eclair.router.Announcements.makeNodeAnnouncement import fr.acinq.eclair.router.BaseRouterSpec.channelHopFromUpdate @@ -554,7 +554,7 @@ class RouteCalculationSpec extends AnyFunSuite with ParallelTestExecution { val publicChannels = channels.map { case (shortChannelId, announcement) => val HopRelayParams.FromAnnouncement(update) = edges.find(_.desc.shortChannelId == shortChannelId).get.params val (update_1_opt, update_2_opt) = if (update.channelFlags.isNode1) (Some(update), None) else (None, Some(update)) - val pc = PublicChannel(announcement, ByteVector32.Zeroes, Satoshi(1000), update_1_opt, update_2_opt, None) + val pc = PublicChannel(announcement, TxId(ByteVector32.Zeroes), Satoshi(1000), update_1_opt, update_2_opt, None) (shortChannelId, pc) } @@ -903,26 +903,26 @@ class RouteCalculationSpec extends AnyFunSuite with ParallelTestExecution { val updates = SortedMap( RealShortChannelId(BlockHeight(565643), 1216, 0) -> PublicChannel( ann = makeChannel(ShortChannelId.fromCoordinates("565643x1216x0").success.value.toLong, PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca")), - fundingTxid = ByteVector32.Zeroes, + fundingTxId = TxId(ByteVector32.Zeroes), capacity = DEFAULT_CAPACITY, - update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("565643x1216x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(14), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 10, 4_294_967_295L msat)), - update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("565643x1216x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 0 msat, feeBaseMsat = 1000 msat, 100, 15_000_000_000L msat)), + update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("565643x1216x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(14), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 10, 4_294_967_295L msat)), + update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("565643x1216x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 0 msat, feeBaseMsat = 1000 msat, 100, 15_000_000_000L msat)), meta_opt = None ), RealShortChannelId(BlockHeight(542280), 2156, 0) -> PublicChannel( ann = makeChannel(ShortChannelId.fromCoordinates("542280x2156x0").success.value.toLong, PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278")), - fundingTxid = ByteVector32.Zeroes, + fundingTxId = TxId(ByteVector32.Zeroes), capacity = DEFAULT_CAPACITY, - update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("542280x2156x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(144), htlcMinimumMsat = 1000 msat, feeBaseMsat = 1000 msat, 100, 16_777_000_000L msat)), - update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("542280x2156x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 667 msat, 1, 16_777_000_000L msat)), + update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("542280x2156x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(144), htlcMinimumMsat = 1000 msat, feeBaseMsat = 1000 msat, 100, 16_777_000_000L msat)), + update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("542280x2156x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 667 msat, 1, 16_777_000_000L msat)), meta_opt = None ), RealShortChannelId(BlockHeight(565779), 2711, 0) -> PublicChannel( ann = makeChannel(ShortChannelId.fromCoordinates("565779x2711x0").success.value.toLong, PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")), - fundingTxid = ByteVector32.Zeroes, + fundingTxId = TxId(ByteVector32.Zeroes), capacity = DEFAULT_CAPACITY, - update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("565779x2711x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 100, 230_000_000L msat)), - update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId.fromCoordinates("565779x2711x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = false, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 100, 230_000_000L msat)), + update_1_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("565779x2711x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 100, 230_000_000L msat)), + update_2_opt = Some(ChannelUpdate(ByteVector64.Zeroes, Block.RegtestGenesisBlock.hash, ShortChannelId.fromCoordinates("565779x2711x0").success.value, 0 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = false, isNode1 = false), CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, feeBaseMsat = 1000 msat, 100, 230_000_000L msat)), meta_opt = None ) ) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala index 44945a534a..0744953488 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala @@ -20,7 +20,7 @@ import akka.actor.typed.scaladsl.adapter.actorRefAdapter import akka.actor.{Actor, Props} import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi, Script, Transaction, TxId, TxIn, TxOut} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.RealShortChannelId import fr.acinq.eclair._ @@ -355,7 +355,7 @@ object RoutingSyncSpec { val channelUpdate_21 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv2, priv1.publicKey, shortChannelId, cltvExpiryDelta = CltvExpiryDelta(7), 0 msat, feeBaseMsat = 766000 msat, feeProportionalMillionths = 10, 500000000L msat, timestamp = timestamp) val nodeAnnouncement_1 = makeNodeAnnouncement(priv1, "a", Color(0, 0, 0), List(), TestConstants.Bob.nodeParams.features.nodeAnnouncementFeatures()) val nodeAnnouncement_2 = makeNodeAnnouncement(priv2, "b", Color(0, 0, 0), List(), Features.empty) - val publicChannel = PublicChannel(channelAnn_12, ByteVector32.Zeroes, Satoshi(0), Some(channelUpdate_12), Some(channelUpdate_21), None) + val publicChannel = PublicChannel(channelAnn_12, TxId(ByteVector32.Zeroes), Satoshi(0), Some(channelUpdate_12), Some(channelUpdate_21), None) (publicChannel, nodeAnnouncement_1, nodeAnnouncement_2) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/testutils/PimpTestProbe.scala b/eclair-core/src/test/scala/fr/acinq/eclair/testutils/PimpTestProbe.scala index aa547661db..be46dc636a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/testutils/PimpTestProbe.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/testutils/PimpTestProbe.scala @@ -1,7 +1,7 @@ package fr.acinq.eclair.testutils import akka.testkit.TestProbe -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Satoshi, TxId} import fr.acinq.eclair.MilliSatoshi import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{WatchFundingConfirmed, WatchFundingSpent, WatchPublished, WatchTxConfirmed} import fr.acinq.eclair.channel.AvailableBalanceChanged @@ -22,19 +22,19 @@ case class PimpTestProbe(probe: TestProbe) extends Assertions { msg } - def expectWatchFundingSpent(txid: ByteVector32, hints_opt: Option[Set[ByteVector32]] = None): WatchFundingSpent = + def expectWatchFundingSpent(txid: TxId, hints_opt: Option[Set[TxId]] = None): WatchFundingSpent = expectMsgTypeHaving[WatchFundingSpent](w => { assert(w.txId == txid, "txid") hints_opt.foreach(hints => assert(hints == w.hints)) }) - def expectWatchFundingConfirmed(txid: ByteVector32): WatchFundingConfirmed = + def expectWatchFundingConfirmed(txid: TxId): WatchFundingConfirmed = expectMsgTypeHaving[WatchFundingConfirmed](w => assert(w.txId == txid, "txid")) - def expectWatchTxConfirmed(txid: ByteVector32): WatchTxConfirmed = + def expectWatchTxConfirmed(txid: TxId): WatchTxConfirmed = expectMsgTypeHaving[WatchTxConfirmed](w => assert(w.txId == txid, "txid")) - def expectWatchPublished(txid: ByteVector32): WatchPublished = + def expectWatchPublished(txid: TxId): WatchPublished = expectMsgTypeHaving[WatchPublished](w => assert(w.txId == txid, "txid")) def expectAvailableBalanceChanged(balance: MilliSatoshi, capacity: Satoshi): AvailableBalanceChanged = diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala index 367a70e249..8f05b07488 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala @@ -124,7 +124,7 @@ trait TestVectorsSpec extends AnyFunSuite with Logging { val fundingAmount = fundingTx.txOut(0).amount logger.info(s"# funding-tx: $fundingTx}") - val commitmentInput = Funding.makeFundingInputInfo(fundingTx.hash, 0, fundingAmount, Local.funding_pubkey, Remote.funding_pubkey) + val commitmentInput = Funding.makeFundingInputInfo(fundingTx.txid, 0, fundingAmount, Local.funding_pubkey, Remote.funding_pubkey) val obscured_tx_number = Transactions.obscuredCommitTxNumber(42, isInitiator = true, Local.payment_basepoint, Remote.payment_basepoint) assert(obscured_tx_number == (0x2bb038521914L ^ 42L)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala index 3dfcae02ea..09264cca83 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala @@ -19,7 +19,8 @@ package fr.acinq.eclair.transactions import fr.acinq.bitcoin.SigHash._ import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, ripemd160, sha256} import fr.acinq.bitcoin.scalacompat.Script.{pay2wpkh, pay2wsh, write} -import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, Crypto, MilliBtc, MilliBtcDouble, OutPoint, Protocol, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, millibtc2satoshi} +import fr.acinq.bitcoin.scalacompat.{Block, Btc, ByteVector32, Crypto, MilliBtc, MilliBtcDouble, OutPoint, Protocol, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, millibtc2satoshi} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel.Helpers.Funding @@ -50,21 +51,21 @@ class TransactionsSpec extends AnyFunSuite with Logging { val localHtlcPriv = PrivateKey(randomBytes32()) val remoteHtlcPriv = PrivateKey(randomBytes32()) val finalPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32()).publicKey)) - val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) + val commitInput = Funding.makeFundingInputInfo(randomTxId(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) val toLocalDelay = CltvExpiryDelta(144) val localDustLimit = Satoshi(546) val feeratePerKw = FeeratePerKw(22000 sat) test("extract csv and cltv timeouts") { - val parentTxId1 = randomBytes32() - val parentTxId2 = randomBytes32() - val parentTxId3 = randomBytes32() + val parentTxId1 = randomTxId() + val parentTxId2 = randomTxId() + val parentTxId3 = randomTxId() val txIn = Seq( - TxIn(OutPoint(parentTxId1.reverse, 3), Nil, 3), - TxIn(OutPoint(parentTxId2.reverse, 1), Nil, 4), - TxIn(OutPoint(parentTxId3.reverse, 0), Nil, 5), - TxIn(OutPoint(randomBytes32(), 4), Nil, 0), - TxIn(OutPoint(parentTxId1.reverse, 2), Nil, 5), + TxIn(OutPoint(parentTxId1, 3), Nil, 3), + TxIn(OutPoint(parentTxId2, 1), Nil, 4), + TxIn(OutPoint(parentTxId3, 0), Nil, 5), + TxIn(OutPoint(randomTxId(), 4), Nil, 0), + TxIn(OutPoint(parentTxId1, 2), Nil, 5), ) val tx = Transaction(2, txIn, Nil, 10) val expected = Map( @@ -205,7 +206,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { // we use dummy signatures to compute the weight val p2wpkhWitness = ScriptWitness(Seq(Scripts.der(PlaceHolderSig), PlaceHolderPubKey.value)) val claimAnchorOutputTxWithFees = claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.copy( - txIn = claimAnchorOutputTx.tx.txIn :+ TxIn(OutPoint(randomBytes32(), 3), ByteVector.empty, 0, p2wpkhWitness), + txIn = claimAnchorOutputTx.tx.txIn :+ TxIn(OutPoint(randomTxId(), 3), ByteVector.empty, 0, p2wpkhWitness), txOut = Seq(TxOut(1500 sat, Script.pay2wpkh(randomKey().publicKey))) )) val signedTx = addSigs(claimAnchorOutputTxWithFees, PlaceHolderSig).tx @@ -256,7 +257,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { test("generate valid commitment and htlc transactions (default commitment format)") { val finalPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32()).publicKey)) - val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) + val commitInput = Funding.makeFundingInputInfo(randomTxId(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) // htlc1 and htlc2 are regular IN/OUT htlcs val paymentPreimage1 = randomBytes32() @@ -487,7 +488,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { test("generate valid commitment and htlc transactions (anchor outputs)") { val finalPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32()).publicKey)) - val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) + val commitInput = Funding.makeFundingInputInfo(randomTxId(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) // htlc1, htlc2a and htlc2b are regular IN/OUT htlcs val paymentPreimage1 = randomBytes32() @@ -751,7 +752,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { val remotePaymentPriv = PrivateKey(hex"a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6") val localHtlcPriv = PrivateKey(hex"a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7") val remoteHtlcPriv = PrivateKey(hex"a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8") - val commitInput = Funding.makeFundingInputInfo(ByteVector32(hex"a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0"), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) + val commitInput = Funding.makeFundingInputInfo(TxId.fromValidHex("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0"), 0, Btc(1), 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 @@ -811,7 +812,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { } test("find our output in closing tx") { - val commitInput = Funding.makeFundingInputInfo(randomBytes32(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) + val commitInput = Funding.makeFundingInputInfo(randomTxId(), 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) val localPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32()).publicKey)) val remotePubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32()).publicKey)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala index 1814d3b31e..cde6a80a7d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.wire.internal.channel import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, Crypto, DeterministicWallet, Satoshi, SatoshiLong, Transaction, TxIn} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto, DeterministicWallet, Satoshi, SatoshiLong, Transaction, TxId, TxIn} import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.Helpers.Funding @@ -300,12 +300,12 @@ object ChannelCodecsSpec { val normal: DATA_NORMAL = makeChannelDataNormal(htlcs, Map(42L -> Origin.LocalCold(UUID.randomUUID), 15000L -> Origin.ChannelRelayedCold(ByteVector32(ByteVector.fill(32)(42)), 43, 11000000 msat, 10000000 msat))) def makeChannelDataNormal(htlcs: Seq[DirectedHtlc], origins: Map[Long, Origin]): DATA_NORMAL = { - val channelUpdate = Announcements.makeChannelUpdate(ByteVector32(ByteVector.fill(32)(1)), randomKey(), randomKey().publicKey, ShortChannelId(142553), CltvExpiryDelta(42), 15 msat, 575 msat, 53, Channel.MAX_FUNDING_WITHOUT_WUMBO.toMilliSatoshi) + val channelUpdate = Announcements.makeChannelUpdate(BlockHash(ByteVector32(ByteVector.fill(32)(1))), randomKey(), randomKey().publicKey, ShortChannelId(142553), CltvExpiryDelta(42), 15 msat, 575 msat, 53, Channel.MAX_FUNDING_WITHOUT_WUMBO.toMilliSatoshi) val fundingTx = Transaction.read("0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000") val fundingAmount = fundingTx.txOut.head.amount val fundingTxIndex = 0 val remoteFundingPubKey = PrivateKey(ByteVector32(ByteVector.fill(32)(1)) :+ 1.toByte).publicKey - val commitmentInput = Funding.makeFundingInputInfo(fundingTx.hash, 0, fundingAmount, channelKeyManager.fundingPublicKey(localParams.fundingKeyPath, fundingTxIndex).publicKey, remoteFundingPubKey) + val commitmentInput = Funding.makeFundingInputInfo(fundingTx.txid, 0, fundingAmount, channelKeyManager.fundingPublicKey(localParams.fundingKeyPath, fundingTxIndex).publicKey, remoteFundingPubKey) val remoteSig = ByteVector64(hex"2148d2d4aac8c793eb82d31bcf22d4db707b9fd7eee1b89b4b1444c9e19ab7172bab8c3d997d29163fa0cb255c75afb8ade13617ad1350c1515e9be4a222a04d") val commitTx = Transaction( version = 2, @@ -318,7 +318,7 @@ object ChannelCodecsSpec { lockTime = 0 ) val localCommit = LocalCommit(0, CommitmentSpec(htlcs.toSet, FeeratePerKw(1500 sat), 50000000 msat, 70000000 msat), CommitTxAndRemoteSig(CommitTx(commitmentInput, commitTx), remoteSig), Nil) - val remoteCommit = RemoteCommit(0, CommitmentSpec(htlcs.map(_.opposite).toSet, FeeratePerKw(1500 sat), 50000 msat, 700000 msat), ByteVector32(hex"0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey) + val remoteCommit = RemoteCommit(0, CommitmentSpec(htlcs.map(_.opposite).toSet, FeeratePerKw(1500 sat), 50000 msat, 700000 msat), TxId.fromValidHex("0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey) val channelId = htlcs.headOption.map(_.add.channelId).getOrElse(ByteVector32.Zeroes) val channelFlags = ChannelFlags.Public val commitments = Commitments( diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1Spec.scala index c7fecf052a..e7f775ba4d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1Spec.scala @@ -3,14 +3,15 @@ package fr.acinq.eclair.wire.internal.channel.version1 import akka.actor.ActorSystem import akka.testkit.TestProbe import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath -import fr.acinq.bitcoin.scalacompat.{OutPoint, Satoshi, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{OutPoint, SatoshiLong} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.fee.FeeratePerKw -import fr.acinq.eclair.channel.{Origin, RemoteParams} +import fr.acinq.eclair.channel.Origin import fr.acinq.eclair.transactions.{CommitmentSpec, DirectedHtlc, IncomingHtlc, OutgoingHtlc} import fr.acinq.eclair.wire.internal.channel.version0.ChannelTypes0.ChannelVersion import fr.acinq.eclair.wire.internal.channel.version1.ChannelCodecs1.Codecs._ import fr.acinq.eclair.wire.protocol.UpdateAddHtlc -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, MilliSatoshiLong, TestConstants, UInt64, randomBytes32, randomKey} +import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, MilliSatoshiLong, TestConstants, randomBytes32} import org.scalatest.funsuite.AnyFunSuite import scodec.bits._ import scodec.{Attempt, DecodeResult} @@ -154,10 +155,10 @@ class ChannelCodecs1Spec extends AnyFunSuite { test("encode/decode map of spending txes") { val map = Map( - OutPoint(randomBytes32(), 42) -> randomBytes32(), - OutPoint(randomBytes32(), 14502) -> randomBytes32(), - OutPoint(randomBytes32(), 0) -> randomBytes32(), - OutPoint(randomBytes32(), 454513) -> randomBytes32() + OutPoint(randomTxId(), 42) -> randomTxId(), + OutPoint(randomTxId(), 14502) -> randomTxId(), + OutPoint(randomTxId(), 0) -> randomTxId(), + OutPoint(randomTxId(), 454513) -> randomTxId() ) assert(spentMapCodec.decodeValue(spentMapCodec.encode(map).require).require == map) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala index fb065d51f0..3aa76a4714 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala @@ -1,10 +1,11 @@ package fr.acinq.eclair.wire.internal.channel.version2 import fr.acinq.bitcoin.scalacompat.{ByteVector64, OutPoint, Transaction} +import fr.acinq.eclair.Features +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.channel.{ChannelConfig, ChannelDataWithCommitments, ChannelFeatures, HtlcTxAndRemoteSig} import fr.acinq.eclair.wire.internal.channel.version2.ChannelCodecs2.Codecs._ import fr.acinq.eclair.wire.internal.channel.version2.ChannelCodecs2.channelDataCodec -import fr.acinq.eclair.{Features, randomBytes32} import org.scalatest.funsuite.AnyFunSuite import scodec.bits.HexStringSyntax @@ -15,10 +16,10 @@ class ChannelCodecs2Spec extends AnyFunSuite { test("encode/decode map of spending txs") { val map = Map( - OutPoint(randomBytes32(), 42) -> Transaction.read("020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000"), - OutPoint(randomBytes32(), 14502) -> Transaction.read("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80094a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994e80300000000000022002010f88bf09e56f14fb4543fd26e47b0db50ea5de9cf3fc46434792471082621aed0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a4c9e6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cf8f902751006923e4062f5dbf55f8475bef08f4b5ac060d219bbff6c1a4431b02206006c515754ffc1f4f263004f61082e1fe4241449629da9096b0679e7e30972201473044022076a51aed1bd085487a7023f2ca8a87544a60a5b7277805b614b6ff7d36f1a44c02207ffac246b6572f3b4c9a7867ffa97c203500eebbf14659df78cfa0fadea22a6401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"), - OutPoint(randomBytes32(), 0) -> Transaction.read("02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a040000000001000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402203c3a699fb80a38112aafd73d6e3a9b7d40bc2c3ed8b7fbc182a20f43b215172202204e71821b984d1af52c4b8e2cd4c572578c12a965866130c2345f61e4c2d3fef48347304402205bcfa92f83c69289a412b0b6dd4f2a0fe0b0fc2d45bd74706e963257a09ea24902203783e47883e60b86240e877fcbf33d50b1742f65bc93b3162d1be26583b367ee012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000"), - OutPoint(randomBytes32(), 454513) -> Transaction.read("02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b00000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b014730440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000") + OutPoint(randomTxId(), 42) -> Transaction.read("020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000"), + OutPoint(randomTxId(), 14502) -> Transaction.read("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80094a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994e80300000000000022002010f88bf09e56f14fb4543fd26e47b0db50ea5de9cf3fc46434792471082621aed0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a4c9e6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cf8f902751006923e4062f5dbf55f8475bef08f4b5ac060d219bbff6c1a4431b02206006c515754ffc1f4f263004f61082e1fe4241449629da9096b0679e7e30972201473044022076a51aed1bd085487a7023f2ca8a87544a60a5b7277805b614b6ff7d36f1a44c02207ffac246b6572f3b4c9a7867ffa97c203500eebbf14659df78cfa0fadea22a6401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"), + OutPoint(randomTxId(), 0) -> Transaction.read("02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a040000000001000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402203c3a699fb80a38112aafd73d6e3a9b7d40bc2c3ed8b7fbc182a20f43b215172202204e71821b984d1af52c4b8e2cd4c572578c12a965866130c2345f61e4c2d3fef48347304402205bcfa92f83c69289a412b0b6dd4f2a0fe0b0fc2d45bd74706e963257a09ea24902203783e47883e60b86240e877fcbf33d50b1742f65bc93b3162d1be26583b367ee012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000"), + OutPoint(randomTxId(), 454513) -> Transaction.read("02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b00000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b014730440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000") ) assert(spentMapCodec.decodeValue(spentMapCodec.encode(map).require).require == map) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala index 4eb7d3cf65..f4e8700965 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala @@ -4,6 +4,7 @@ import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.{DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features.{ChannelRangeQueries, PaymentSecret, VariableLengthOnion} +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.{InteractiveTxParams, PartiallySignedSharedTransaction, RequireConfirmedInputs, SharedTransaction} @@ -120,7 +121,7 @@ class ChannelCodecs4Spec extends AnyFunSuite { test("encode/decode rbf status") { val channelId = randomBytes32() - val fundingInput = InputInfo(OutPoint(randomBytes32(), 3), TxOut(175_000 sat, Script.pay2wpkh(randomKey().publicKey)), Nil) + val fundingInput = InputInfo(OutPoint(randomTxId(), 3), TxOut(175_000 sat, Script.pay2wpkh(randomKey().publicKey)), Nil) val fundingTx = SharedTransaction( sharedInput_opt = None, sharedOutput = InteractiveTxBuilder.Output.Shared(UInt64(8), ByteVector.empty, 100_000_600 msat, 74_000_400 msat, 0 msat), @@ -135,9 +136,9 @@ class ChannelCodecs4Spec extends AnyFunSuite { val waitingForSigs = InteractiveTxSigningSession.WaitingForSigs( InteractiveTxParams(channelId, isInitiator = true, 100_000 sat, 75_000 sat, None, randomKey().publicKey, Nil, 0, 330 sat, FeeratePerKw(500 sat), RequireConfirmedInputs(forLocal = false, forRemote = false)), fundingTxIndex = 0, - PartiallySignedSharedTransaction(fundingTx, TxSignatures(channelId, randomBytes32(), Nil)), + PartiallySignedSharedTransaction(fundingTx, TxSignatures(channelId, randomTxId(), Nil)), Left(UnsignedLocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(1000 sat), 100_000_000 msat, 75_000_000 msat), commitTx, Nil)), - RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(1000 sat), 75_000_000 msat, 100_000_000 msat), randomBytes32(), randomKey().publicKey) + RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(1000 sat), 75_000_000 msat, 100_000_000 msat), randomTxId(), randomKey().publicKey) ) val testCases = Map( RbfStatus.NoRbf -> RbfStatus.NoRbf, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/ExtendedQueriesCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/ExtendedQueriesCodecsSpec.scala index ae6fe2caea..d9e07d944c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/ExtendedQueriesCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/ExtendedQueriesCodecsSpec.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.wire.protocol -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64} import fr.acinq.eclair.router.Sync import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._ import fr.acinq.eclair.wire.protocol.ReplyChannelRangeTlv._ @@ -65,7 +65,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode query_short_channel_ids (no optional data)") { val query_short_channel_id = QueryShortChannelIds( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty) @@ -76,7 +76,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode query_short_channel_ids (with optional data)") { val query_short_channel_id = QueryShortChannelIds( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.UNCOMPRESSED, List(1.toByte, 2.toByte, 3.toByte, 4.toByte, 5.toByte)))) @@ -87,7 +87,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode query_short_channel_ids (with optional data including unknown data)") { val query_short_channel_id = QueryShortChannelIds( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream( Set[QueryShortChannelIdsTlv](QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.UNCOMPRESSED, List(1.toByte, 2.toByte, 3.toByte, 4.toByte, 5.toByte))), @@ -102,7 +102,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode reply_channel_range (no optional data)") { val replyChannelRange = ReplyChannelRange( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, BlockHeight(1), 100, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), @@ -115,7 +115,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode reply_channel_range (with optional timestamps)") { val replyChannelRange = ReplyChannelRange( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, BlockHeight(1), 100, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), @@ -129,7 +129,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("encode reply_channel_range (with optional timestamps, checksums, and unknown data)") { val replyChannelRange = ReplyChannelRange( - Block.RegtestGenesisBlock.blockId, + Block.RegtestGenesisBlock.hash, BlockHeight(1), 100, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), @@ -149,7 +149,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("compute checksums correctly") { val update = ChannelUpdate( - chainHash = ByteVector32.fromValidHex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), + chainHash = BlockHash(ByteVector32.fromValidHex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")), signature = ByteVector64.fromValidHex("76df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c80293282"), shortChannelId = ShortChannelId.fromCoordinates("103x1x0").success.value, timestamp = TimestampSecond(1565587763L), @@ -170,7 +170,7 @@ class ExtendedQueriesCodecsSpec extends AnyFunSuite { test("compute checksums correctly (cln test)") { val update = ChannelUpdate( - chainHash = ByteVector32.fromValidHex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), + chainHash = BlockHash(ByteVector32.fromValidHex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")), signature = ByteVector64.fromValidHex("06737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c"), shortChannelId = ShortChannelId.fromCoordinates("109x1x0").success.value, timestamp = TimestampSecond(1565587765L), diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala index cc634f6b37..d768752b16 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala @@ -18,9 +18,10 @@ package fr.acinq.eclair.wire.protocol import com.google.common.base.Charsets import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, OutPoint, SatoshiLong, ScriptWitness, Transaction} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, OutPoint, SatoshiLong, ScriptWitness, Transaction, TxId} import fr.acinq.eclair.FeatureSupport.Optional import fr.acinq.eclair.Features.DataLossProtect +import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.{ChannelFlags, ChannelTypes} @@ -54,9 +55,9 @@ class LightningMessageCodecsSpec extends AnyFunSuite { def publicKey(fill: Byte) = PrivateKey(ByteVector.fill(32)(fill)).publicKey test("encode/decode init message") { - case class TestCase(encoded: ByteVector, rawFeatures: ByteVector, networks: List[ByteVector32], address: Option[IPAddress], valid: Boolean, reEncoded: Option[ByteVector] = None) - val chainHash1 = ByteVector32(hex"0101010101010101010101010101010101010101010101010101010101010101") - val chainHash2 = ByteVector32(hex"0202020202020202020202020202020202020202020202020202020202020202") + case class TestCase(encoded: ByteVector, rawFeatures: ByteVector, networks: List[BlockHash], address: Option[IPAddress], valid: Boolean, reEncoded: Option[ByteVector] = None) + val chainHash1 = BlockHash(ByteVector32(hex"0101010101010101010101010101010101010101010101010101010101010101")) + val chainHash2 = BlockHash(ByteVector32(hex"0202020202020202020202020202020202020202020202020202020202020202")) val remoteAddress1 = IPv4(InetAddress.getByAddress(Array[Byte](140.toByte, 82.toByte, 121.toByte, 3.toByte)).asInstanceOf[Inet4Address], 9735) val remoteAddress2 = IPv6(InetAddress.getByAddress(hex"b643 8bb1 c1f9 0556 487c 0acb 2ba3 3cc2".toArray).asInstanceOf[Inet6Address], 9736) val testCases = Seq( @@ -123,7 +124,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { val signature = randomBytes64() val key = randomKey() val point = randomKey().publicKey - val txHash = randomBytes32() + val txId = randomTxId() val randomData = randomBytes(42) val tlvTag = UInt64(hex"47010000") @@ -133,7 +134,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { hex"0023" ++ channelId ++ signature ++ hex"fe47010000 07 cccccccccccccc" -> FundingSigned(channelId, signature, TlvStream[FundingSignedTlv](Set.empty[FundingSignedTlv], Set(GenericTlv(tlvTag, hex"cccccccccccccc")))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point), - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"00 20" ++ txHash.bytes -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txHash))), + hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"00 20" ++ txId.value.reverse -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txId))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"fe47010000 00" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream[ChannelReestablishTlv](Set.empty[ChannelReestablishTlv], Set(GenericTlv(tlvTag, ByteVector.empty)))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"fe47010000 07 bbbbbbbbbbbbbb" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream[ChannelReestablishTlv](Set.empty[ChannelReestablishTlv], Set(GenericTlv(tlvTag, hex"bbbbbbbbbbbbbb")))), @@ -214,7 +215,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { } test("encode/decode open_channel") { - val defaultOpen = OpenChannel(ByteVector32.Zeroes, ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private) + val defaultOpen = OpenChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private) // Legacy encoding that omits the upfront_shutdown_script and trailing tlv stream. // To allow extending all messages with TLV streams, the upfront_shutdown_script was moved to a TLV stream extension // in https://github.com/lightningnetwork/lightning-rfc/pull/714 and made mandatory when including a TLV stream. @@ -286,7 +287,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { } test("encode/decode open_channel (dual funding)") { - val defaultOpen = OpenDualFundedChannel(ByteVector32.Zeroes, ByteVector32.One, FeeratePerKw(5000 sat), FeeratePerKw(4000 sat), 250_000 sat, 500 sat, UInt64(50_000), 15 msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), ChannelFlags(true)) + val defaultOpen = OpenDualFundedChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.One, FeeratePerKw(5000 sat), FeeratePerKw(4000 sat), 250_000 sat, 500 sat, UInt64(50_000), 15 msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), ChannelFlags(true)) val defaultEncoded = hex"0040 0000000000000000000000000000000000000000000000000000000000000000 0100000000000000000000000000000000000000000000000000000000000000 00001388 00000fa0 000000000003d090 00000000000001f4 000000000000c350 000000000000000f 0090 01e3 0009eb10 031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f 024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766 02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337 03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b 0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7 03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a 02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f 01" val testCases = Seq( defaultOpen -> defaultEncoded, @@ -304,7 +305,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { } test("decode open_channel with unknown channel flags (dual funding)") { - val defaultOpen = OpenDualFundedChannel(ByteVector32.Zeroes, ByteVector32.One, FeeratePerKw(5000 sat), FeeratePerKw(4000 sat), 250_000 sat, 500 sat, UInt64(50_000), 15 msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), ChannelFlags(true)) + val defaultOpen = OpenDualFundedChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.One, FeeratePerKw(5000 sat), FeeratePerKw(4000 sat), 250_000 sat, 500 sat, UInt64(50_000), 15 msat, CltvExpiryDelta(144), 483, 650_000, publicKey(1), publicKey(2), publicKey(3), publicKey(4), publicKey(5), publicKey(6), publicKey(7), ChannelFlags(true)) val defaultEncodedWithoutFlags = hex"0040 0000000000000000000000000000000000000000000000000000000000000000 0100000000000000000000000000000000000000000000000000000000000000 00001388 00000fa0 000000000003d090 00000000000001f4 000000000000c350 000000000000000f 0090 01e3 0009eb10 031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f 024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766 02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337 03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b 0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7 03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a 02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f" val testCases = Seq( defaultEncodedWithoutFlags ++ hex"00" -> ChannelFlags(false), @@ -382,9 +383,9 @@ class LightningMessageCodecsSpec extends AnyFunSuite { test("encode/decode all channel messages") { val unknownTlv = GenericTlv(UInt64(5), ByteVector.fromValidHex("deadbeef")) val msgs = List( - OpenChannel(randomBytes32(), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private), + OpenChannel(BlockHash(randomBytes32()), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private), AcceptChannel(randomBytes32(), 3 sat, UInt64(4), 5 sat, 6 msat, 7, CltvExpiryDelta(8), 9, publicKey(1), point(2), point(3), point(4), point(5), point(6)), - FundingCreated(randomBytes32(), bin32(0), 3, randomBytes64()), + FundingCreated(randomBytes32(), TxId(ByteVector32.Zeroes), 3, randomBytes64()), FundingSigned(randomBytes32(), randomBytes64()), ChannelReady(randomBytes32(), point(2)), ChannelReady(randomBytes32(), point(2), TlvStream(ChannelReadyTlv.ShortChannelIdTlv(Alias(123456)))), @@ -401,13 +402,13 @@ class LightningMessageCodecsSpec extends AnyFunSuite { NodeAnnouncement(randomBytes64(), Features(DataLossProtect -> Optional), 1 unixsec, randomKey().publicKey, Color(100.toByte, 200.toByte, 300.toByte), "node-alias", IPv4(InetAddress.getByAddress(Array[Byte](192.toByte, 168.toByte, 1.toByte, 42.toByte)).asInstanceOf[Inet4Address], 42000) :: Nil), ChannelUpdate(randomBytes64(), Block.RegtestGenesisBlock.hash, ShortChannelId(1), 2 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags.DUMMY, CltvExpiryDelta(3), 4 msat, 5 msat, 6, 25_000_000 msat), AnnouncementSignatures(randomBytes32(), RealShortChannelId(42), randomBytes64(), randomBytes64()), - GossipTimestampFilter(Block.RegtestGenesisBlock.blockId, 100000 unixsec, 1500), - QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), - QueryChannelRange(Block.RegtestGenesisBlock.blockId, + GossipTimestampFilter(Block.RegtestGenesisBlock.hash, 100000 unixsec, 1500), + QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), + QueryChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(100000), 1500, TlvStream(Set[QueryChannelRangeTlv](QueryChannelRangeTlv.QueryFlags(QueryChannelRangeTlv.QueryFlags.WANT_ALL)), Set(unknownTlv))), - ReplyChannelRange(Block.RegtestGenesisBlock.blockId, + ReplyChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(100000), 1500, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream( @@ -442,13 +443,13 @@ class LightningMessageCodecsSpec extends AnyFunSuite { test("non-reg encoding type") { val refs = Map( hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001900000000000000008e0000000000003c69000000000045a6c4" - -> QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), + -> QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001601789c636000833e08659309a65c971d0100126e02e3" - -> QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), + -> QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty), hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001900000000000000008e0000000000003c69000000000045a6c4010400010204" - -> QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.UNCOMPRESSED, List(1, 2, 4)))), + -> QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.UNCOMPRESSED, List(1, 2, 4)))), hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001601789c636000833e08659309a65c971d0100126e02e3010c01789c6364620100000e0008" - -> QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) + -> QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) ) refs.forall { @@ -460,39 +461,38 @@ class LightningMessageCodecsSpec extends AnyFunSuite { case class TestItem(msg: Any, hex: String) test("test vectors for extended channel queries ") { - val refs = Map( - QueryChannelRange(Block.RegtestGenesisBlock.blockId, BlockHeight(100000), 1500, TlvStream.empty) -> - hex"01070f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000186a0000005dc", - QueryChannelRange(Block.RegtestGenesisBlock.blockId, + QueryChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(100000), 1500, TlvStream.empty) -> + hex"010706226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000186a0000005dc", + QueryChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(35000), 100, TlvStream(QueryChannelRangeTlv.QueryFlags(QueryChannelRangeTlv.QueryFlags.WANT_ALL))) -> - hex"01070f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000088b800000064010103", - ReplyChannelRange(Block.RegtestGenesisBlock.blockId, BlockHeight(756230), 1500, 1, + hex"010706226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000088b800000064010103", + ReplyChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(756230), 1500, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), None, None) -> - hex"01080f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000b8a06000005dc01001900000000000000008e0000000000003c69000000000045a6c4", - ReplyChannelRange(Block.RegtestGenesisBlock.blockId, BlockHeight(1600), 110, 1, + hex"010806226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000b8a06000005dc01001900000000000000008e0000000000003c69000000000045a6c4", + ReplyChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(1600), 110, 1, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(265462))), None, None) -> - hex"01080f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000006400000006e01001601789c636000833e08659309a65878be010010a9023a", - ReplyChannelRange(Block.RegtestGenesisBlock.blockId, BlockHeight(122334), 1500, 1, + hex"010806226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000006400000006e01001601789c636000833e08659309a65878be010010a9023a", + ReplyChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(122334), 1500, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(12355), RealShortChannelId(489686), RealShortChannelId(4645313))), Some(EncodedTimestamps(EncodingType.UNCOMPRESSED, List(Timestamps(164545 unixsec, 948165 unixsec), Timestamps(489645 unixsec, 4786864 unixsec), Timestamps(46456 unixsec, 9788415 unixsec)))), Some(EncodedChecksums(List(Checksums(1111, 2222), Checksums(3333, 4444), Checksums(5555, 6666))))) -> - hex"01080f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22060001ddde000005dc01001900000000000000304300000000000778d6000000000046e1c1011900000282c1000e77c5000778ad00490ab00000b57800955bff031800000457000008ae00000d050000115c000015b300001a0a", - ReplyChannelRange(Block.RegtestGenesisBlock.blockId, BlockHeight(122334), 1500, 1, + hex"010806226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0001ddde000005dc01001900000000000000304300000000000778d6000000000046e1c1011900000282c1000e77c5000778ad00490ab00000b57800955bff031800000457000008ae00000d050000115c000015b300001a0a", + ReplyChannelRange(Block.RegtestGenesisBlock.hash, BlockHeight(122334), 1500, 1, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(12355), RealShortChannelId(489686), RealShortChannelId(4645313))), Some(EncodedTimestamps(EncodingType.COMPRESSED_ZLIB, List(Timestamps(164545 unixsec, 948165 unixsec), Timestamps(489645 unixsec, 4786864 unixsec), Timestamps(46456 unixsec, 9788415 unixsec)))), Some(EncodedChecksums(List(Checksums(1111, 2222), Checksums(3333, 4444), Checksums(5555, 6666))))) -> - hex"01080f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22060001ddde000005dc01001801789c63600001036730c55e710d4cbb3d3c080017c303b1012201789c63606a3ac8c0577e9481bd622d8327d7060686ad150c53a3ff0300554707db031800000457000008ae00000d050000115c000015b300001a0a", - QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty) -> - hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001900000000000000008e0000000000003c69000000000045a6c4", - QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(4564), RealShortChannelId(178622), RealShortChannelId(4564676))), TlvStream.empty) -> - hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001801789c63600001c12b608a69e73e30edbaec0800203b040e", - QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(12232), RealShortChannelId(15556), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) -> - hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22060019000000000000002fc80000000000003cc4000000000045a6c4010c01789c6364620100000e0008", - QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(14200), RealShortChannelId(46645), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) -> - hex"01050f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206001801789c63600001f30a30c5b0cd144cb92e3b020017c6034a010c01789c6364620100000e0008" + hex"010806226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0001ddde000005dc01001801789c63600001036730c55e710d4cbb3d3c080017c303b1012201789c63606a3ac8c0577e9481bd622d8327d7060686ad150c53a3ff0300554707db031800000457000008ae00000d050000115c000015b300001a0a", + QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(142), RealShortChannelId(15465), RealShortChannelId(4564676))), TlvStream.empty) -> + hex"010506226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f001900000000000000008e0000000000003c69000000000045a6c4", + QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(4564), RealShortChannelId(178622), RealShortChannelId(4564676))), TlvStream.empty) -> + hex"010506226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f001801789c63600001c12b608a69e73e30edbaec0800203b040e", + QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(12232), RealShortChannelId(15556), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) -> + hex"010506226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0019000000000000002fc80000000000003cc4000000000045a6c4010c01789c6364620100000e0008", + QueryShortChannelIds(Block.RegtestGenesisBlock.hash, EncodedShortChannelIds(EncodingType.COMPRESSED_ZLIB, List(RealShortChannelId(14200), RealShortChannelId(46645), RealShortChannelId(4564676))), TlvStream(QueryShortChannelIdsTlv.EncodedQueryFlags(EncodingType.COMPRESSED_ZLIB, List(1, 2, 4)))) -> + hex"010506226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f001801789c63600001f30a30c5b0cd144cb92e3b020017c6034a010c01789c6364620100000e0008" ) val items = refs.map { case (obj, refbin) => @@ -555,7 +555,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { // this was generated by c-lightning val bin = hex"010258fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf1792306226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0005a100000200005bc75919010100060000000000000001000000010000000a000000003a699d00" val update = lightningMessageCodec.decode(bin.bits).require.value.asInstanceOf[ChannelUpdate] - assert(update == ChannelUpdate(ByteVector64(hex"58fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf17923"), ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), ShortChannelId(0x5a10000020000L), 1539791129 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(6), 1 msat, 1 msat, 10, 980_000_000 msat)) + assert(update == ChannelUpdate(ByteVector64(hex"58fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf17923"), BlockHash(ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")), ShortChannelId(0x5a10000020000L), 1539791129 unixsec, ChannelUpdate.MessageFlags(dontForward = false), ChannelUpdate.ChannelFlags(isEnabled = true, isNode1 = false), CltvExpiryDelta(6), 1 msat, 1 msat, 10, 980_000_000 msat)) val nodeId = PublicKey(hex"03370c9bac836e557eb4f017fe8f9cc047f44db39c1c4e410ff0f7be142b817ae4") assert(Announcements.checkSig(update, nodeId)) val bin2 = ByteVector(lightningMessageCodec.encode(update).require.toByteArray) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/OfferTypesSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/OfferTypesSpec.scala index 2a9cba1c1b..623a54c384 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/OfferTypesSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/OfferTypesSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.wire.protocol import fr.acinq.bitcoin.Bech32 import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features.BasicMultiPartPayment import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.{BlindedNode, BlindedRoute} @@ -145,7 +145,7 @@ class OfferTypesSpec extends AnyFunSuite { assert(!otherChain.isValid) } { - val (chain1, chain2) = (randomBytes32(), randomBytes32()) + val (chain1, chain2) = (BlockHash(randomBytes32()), BlockHash(randomBytes32())) val offer = Offer(TlvStream(OfferChains(Seq(chain1, chain2)), OfferAmount(100 msat), OfferDescription("offer with chains"), OfferNodeId(randomKey().publicKey))) val payerKey = randomKey() val request1 = InvoiceRequest(offer, 100 msat, 1, Features.empty, payerKey, chain1) diff --git a/eclair-front/src/main/scala/fr/acinq/eclair/router/FrontRouter.scala b/eclair-front/src/main/scala/fr/acinq/eclair/router/FrontRouter.scala index 676a2eef66..87e16e93e8 100644 --- a/eclair-front/src/main/scala/fr/acinq/eclair/router/FrontRouter.scala +++ b/eclair-front/src/main/scala/fr/acinq/eclair/router/FrontRouter.scala @@ -20,15 +20,14 @@ import akka.Done import akka.actor.{ActorRef, Props} import akka.event.Logging.MDC import akka.event.LoggingAdapter -import fr.acinq.bitcoin.scalacompat.ByteVector32 import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey +import fr.acinq.bitcoin.scalacompat.{ByteVector32, TxId} import fr.acinq.eclair.Logs.LogCategory -import fr.acinq.eclair.RealShortChannelId import fr.acinq.eclair.crypto.TransportHandler import fr.acinq.eclair.io.Peer.PeerRoutingMessage import fr.acinq.eclair.router.Router._ import fr.acinq.eclair.wire.protocol._ -import fr.acinq.eclair.{FSMDiagnosticActorLogging, Logs, ShortChannelId, getSimpleClassName} +import fr.acinq.eclair.{FSMDiagnosticActorLogging, Logs, RealShortChannelId, getSimpleClassName} import kamon.Kamon import kamon.metric.Counter @@ -265,7 +264,7 @@ object FrontRouter { case ChannelsDiscovered(channels) => log.debug("adding {} channels", channels.size) val channels1 = channels.foldLeft(SortedMap.empty[RealShortChannelId, PublicChannel]) { - case (channels, sc) => channels + (sc.ann.shortChannelId -> PublicChannel(sc.ann, ByteVector32.Zeroes, sc.capacity, sc.u1_opt, sc.u2_opt, None)) + case (channels, sc) => channels + (sc.ann.shortChannelId -> PublicChannel(sc.ann, TxId(ByteVector32.Zeroes), sc.capacity, sc.u1_opt, sc.u2_opt, None)) } val d1 = d.copy(channels = d.channels ++ channels1) if (doRebroadcast) { diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/serde/FormParamExtractors.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/serde/FormParamExtractors.scala index 035a33ea62..1c934fa1aa 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/api/serde/FormParamExtractors.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/serde/FormParamExtractors.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.api.serde import akka.http.scaladsl.unmarshalling.Unmarshaller import akka.util.Timeout import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Satoshi, TxId} import fr.acinq.eclair.api.directives.RouteFormat import fr.acinq.eclair.api.serde.JsonSupport._ import fr.acinq.eclair.blockchain.fee.{ConfirmationPriority, FeeratePerByte} @@ -67,7 +67,7 @@ object FormParamExtractors { implicit val outPointListUnmarshaller: Unmarshaller[String, List[OutPoint]] = listUnmarshaller(outPoint => { val parts = outPoint.split(":") - OutPoint(ByteVector32.fromValidHex(parts.head).reverse, parts.last.toLong) + OutPoint(TxId.fromValidHex(parts.head), parts.last.toLong) }) implicit val base64DataUnmarshaller: Unmarshaller[String, ByteVector] = Unmarshaller.strict { str => ByteVector.fromValidBase64(str) } diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala index 63398d02c4..a0abe0744c 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala @@ -25,7 +25,7 @@ import akka.http.scaladsl.testkit.{RouteTestTimeout, ScalatestRouteTest, WSProbe import akka.util.Timeout import de.heikoseeberger.akkahttpjson4s.Json4sSupport import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, OutPoint, SatoshiLong} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, OutPoint, SatoshiLong, TxId} import fr.acinq.eclair.ApiTypes.ChannelIdentifier import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features.{ChannelRangeQueriesExtended, DataLossProtect} @@ -250,7 +250,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM features = Features(DataLossProtect -> Mandatory, ChannelRangeQueriesExtended -> Optional), nodeId = aliceNodeId, alias = "alice", - chainHash = ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), + chainHash = BlockHash(ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")), network = "regtest", blockHeight = 9999, publicAddresses = NodeAddress.fromParts("127.0.0.1", 9731).get :: Nil, @@ -274,7 +274,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM test("'open' channels") { val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") val channelId = ByteVector32(hex"56d7d6eda04d80138270c49709f1eadb5ab4939e5061309ccdacdb98ce637d0e") - val fundingTxId = ByteVector32(hex"a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") + val fundingTxId = TxId.fromValidHex("a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") val eclair = mock[Eclair] eclair.open(any, any, any, any, any, any, any)(any[Timeout]) returns Future.successful(OpenChannelResponse.Created(channelId, fundingTxId, 100 sat)) @@ -311,7 +311,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM test("'open' channels with standard channelType") { val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") val channelId = ByteVector32(hex"56d7d6eda04d80138270c49709f1eadb5ab4939e5061309ccdacdb98ce637d0e") - val fundingTxId = ByteVector32(hex"a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") + val fundingTxId = TxId.fromValidHex("a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") val eclair = mock[Eclair] eclair.open(any, any, any, any, any, any, any)(any[Timeout]) returns Future.successful(OpenChannelResponse.Created(channelId, fundingTxId, 0 sat)) @@ -332,7 +332,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM test("'open' channels with static_remotekey channelType") { val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") val channelId = ByteVector32(hex"56d7d6eda04d80138270c49709f1eadb5ab4939e5061309ccdacdb98ce637d0e") - val fundingTxId = ByteVector32(hex"a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") + val fundingTxId = TxId.fromValidHex("a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") val eclair = mock[Eclair] eclair.open(any, any, any, any, any, any, any)(any[Timeout]) returns Future.successful(OpenChannelResponse.Created(channelId, fundingTxId, 1 sat)) @@ -353,7 +353,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM test("'open' channels with anchor_outputs channelType") { val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") val channelId = ByteVector32(hex"56d7d6eda04d80138270c49709f1eadb5ab4939e5061309ccdacdb98ce637d0e") - val fundingTxId = ByteVector32(hex"a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") + val fundingTxId = TxId.fromValidHex("a86b3f93c1b2ea3f221159869d6f556cae1ba2622cc8c7eb71c7f4f64e0fbca4") val eclair = mock[Eclair] eclair.open(any, any, any, any, any, any, any)(any[Timeout]) returns Future.successful(OpenChannelResponse.Created(channelId, fundingTxId, 500 sat)) @@ -575,9 +575,9 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM test("'cpfpbumpfees'") { val eclair = mock[Eclair] - eclair.cpfpBumpFees(any, any) returns Future.successful(randomBytes32()) + eclair.cpfpBumpFees(any, any) returns Future.successful(TxId(randomBytes32())) val mockService = new MockService(eclair) - val (txId1, txId2) = (randomBytes32(), randomBytes32()) + val (txId1, txId2) = (TxId(randomBytes32()), TxId(randomBytes32())) Post("/cpfpbumpfees", FormData("targetFeerateSatByte" -> "10", "outpoints" -> s"$txId1:2,$txId2:0,$txId1:13").toEntity) ~> addCredentials(BasicHttpCredentials("", mockApi().password)) ~> @@ -585,7 +585,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM check { assert(handled) assert(status == OK) - eclair.cpfpBumpFees(FeeratePerByte(10 sat), Set(OutPoint(txId1.reverse, 2), OutPoint(txId1.reverse, 13), OutPoint(txId2.reverse, 0))).wasCalled(once) + eclair.cpfpBumpFees(FeeratePerByte(10 sat), Set(OutPoint(txId1, 2), OutPoint(txId1, 13), OutPoint(txId2, 0))).wasCalled(once) } Post("/cpfpbumpfees", FormData("targetFeerateSatByte" -> "10").toEntity) ~> @@ -1032,7 +1032,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM val mockChannelUpdate1 = ChannelUpdate( signature = ByteVector64.fromValidHex("92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679"), - chainHash = ByteVector32.fromValidHex("024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2"), + chainHash = BlockHash(ByteVector32.fromValidHex("024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2")), shortChannelId = RealShortChannelId(BlockHeight(1), 2, 3), timestamp = 0 unixsec, messageFlags = ChannelUpdate.MessageFlags(dontForward = false), diff --git a/pom.xml b/pom.xml index 41c47eea01..15e3349167 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 2.6.20 10.2.7 3.8.16 - 0.29 + 0.30 32.1.1-jre 2.6.3