@@ -407,35 +407,18 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
407407 }
408408 }
409409
410+ def getTransaction (probe : TestProbe , txid : TxId ): Transaction = {
411+ bitcoinrpcclient.invoke(" getrawtransaction" , txid).pipeTo(probe.ref)
412+ Transaction .read(probe.expectMsgType[JString ].values)
413+ }
414+
415+ def getExtraInputsMap (probe : TestProbe , tx : Transaction ): Map [OutPoint , TxOut ] = {
416+ tx.txIn.tail.map(input => input.outPoint -> getTransaction(probe, input.outPoint.txid).txOut(input.outPoint.index.toInt)).toMap
417+ }
418+
410419 test(" commit tx feerate too low, spending anchor output (local commit)" ) {
411420 // we create a new channel key manager that delegates all call to Alice's key manager but track extra utxos passed to the sign() methods
412- val walletInputs = new AtomicReference [Map [OutPoint , TxOut ]](Map .empty)
413- val channelKeyManagerA = TestConstants .Alice .nodeParams.channelKeyManager
414- // @formatter:off
415- val channelKeyManager = new ChannelKeyManager {
416- override def fundingPublicKey (fundingKeyPath : DeterministicWallet .KeyPath , fundingTxIndex : Long ): DeterministicWallet .ExtendedPublicKey = channelKeyManagerA.fundingPublicKey(fundingKeyPath, fundingTxIndex)
417- override def revocationPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManagerA.revocationPoint(channelKeyPath)
418- override def paymentPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManagerA.paymentPoint(channelKeyPath)
419- override def delayedPaymentPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManagerA.delayedPaymentPoint(channelKeyPath)
420- override def htlcPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManagerA.htlcPoint(channelKeyPath)
421- override def commitmentSecret (channelKeyPath : DeterministicWallet .KeyPath , index : Long ): Crypto .PrivateKey = channelKeyManagerA.commitmentSecret(channelKeyPath, index)
422- override def commitmentPoint (channelKeyPath : DeterministicWallet .KeyPath , index : Long ): PublicKey = channelKeyManagerA.commitmentPoint(channelKeyPath, index)
423- override def newFundingKeyPath (isChannelOpener : Boolean ): DeterministicWallet .KeyPath = channelKeyManagerA.newFundingKeyPath(isChannelOpener)
424- override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
425- walletInputs.set(extraUtxos)
426- channelKeyManagerA.sign(tx, publicKey, txOwner, commitmentFormat, extraUtxos)
427- }
428- override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , remotePoint : PublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
429- walletInputs.set(extraUtxos)
430- channelKeyManagerA.sign(tx, publicKey, remotePoint, txOwner, commitmentFormat, extraUtxos)
431- }
432- override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , remoteSecret : Crypto .PrivateKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
433- walletInputs.set(extraUtxos)
434- channelKeyManagerA.sign(tx, publicKey, remoteSecret, txOwner, commitmentFormat, extraUtxos)
435- }
436- override def signChannelAnnouncement (witness : ByteVector , fundingKeyPath : DeterministicWallet .KeyPath ): ByteVector64 = channelKeyManagerA.signChannelAnnouncement(witness, fundingKeyPath)
437- }
438- // @formatter:on
421+ val channelKeyManager = new DummyChannelKeyManager (TestConstants .Alice .nodeParams.channelKeyManager)
439422
440423 withFixture(Seq (500 millibtc), ChannelTypes .AnchorOutputsZeroFeeHtlcTx (), Some (channelKeyManager)) { f =>
441424 import f ._
@@ -455,16 +438,10 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
455438 // check that the wallet input added by the tx funder was passed to the key manager
456439 assert(mempoolTxs.map(_.txid).contains(commitTx.tx.txid))
457440
458- def getTransaction (txid : TxId ): Transaction = {
459- bitcoinrpcclient.invoke(" getrawtransaction" , txid).pipeTo(probe.ref)
460- Transaction .read(probe.expectMsgType[JString ].values)
461- }
462-
463441 // there are 2 transactions in the mempool, the one that is not the commit tx has to be the anchor tx
464- val publishedAnchorTx = getTransaction(mempoolTxs.filterNot(_.txid == commitTx.tx.txid).head.txid)
465- val extraInputs = publishedAnchorTx.txIn.tail.map(input => input.outPoint -> getTransaction(input.outPoint.txid).txOut(input.outPoint.index.toInt)).toMap
442+ val publishedAnchorTx = getTransaction(probe, mempoolTxs.filterNot(_.txid == commitTx.tx.txid).head.txid)
466443 // check that inputs added to the anchor tx match what was passed to our key manager's sign() method
467- assert(walletInputs.get() == extraInputs )
444+ assert(channelKeyManager. walletInputs.get() == getExtraInputsMap(probe, publishedAnchorTx) )
468445
469446 val targetFee = Transactions .weight2fee(targetFeerate, mempoolTxs.map(_.weight).sum.toInt)
470447 val actualFee = mempoolTxs.map(_.fees).sum
@@ -1293,7 +1270,8 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
12931270 }
12941271
12951272 test(" htlc success tx not confirming, lowering output amount" ) {
1296- withFixture(Seq (500 millibtc), ChannelTypes .AnchorOutputsZeroFeeHtlcTx ()) { f =>
1273+ val channelKeyManager = new DummyChannelKeyManager (TestConstants .Alice .nodeParams.channelKeyManager)
1274+ withFixture(Seq (500 millibtc), ChannelTypes .AnchorOutputsZeroFeeHtlcTx (), channelKeyManager_opt = Some (channelKeyManager)) { f =>
12971275 import f ._
12981276
12991277 val initialFeerate = FeeratePerKw (15_000 sat)
@@ -1321,13 +1299,19 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
13211299 assert(htlcSuccessTx2.txid == htlcSuccessTxId2)
13221300 assert(htlcSuccessTx1.fees < htlcSuccessTx2.fees)
13231301 assert(htlcSuccessInputs1 == htlcSuccessInputs2)
1302+
1303+ // check that wallet inputs were passed to the sign() methods
1304+ val publishedHtlcSuccessTx = getTransaction(probe, htlcSuccessTxId2)
1305+ assert(channelKeyManager.walletInputs.get() == getExtraInputsMap(probe, publishedHtlcSuccessTx))
1306+
13241307 val htlcSuccessTargetFee = Transactions .weight2fee(targetFeerate, htlcSuccessTx2.weight.toInt)
13251308 assert(htlcSuccessTargetFee * 0.9 <= htlcSuccessTx2.fees && htlcSuccessTx2.fees <= htlcSuccessTargetFee * 1.1 , s " actualFee= ${htlcSuccessTx2.fees} targetFee= $htlcSuccessTargetFee" )
13261309 }
13271310 }
13281311
13291312 test(" htlc success tx not confirming, adding other wallet inputs" ) {
1330- withFixture(Seq (1_010_000 sat, 10_000 sat), ChannelTypes .AnchorOutputsZeroFeeHtlcTx ()) { f =>
1313+ val channelKeyManager = new DummyChannelKeyManager (TestConstants .Alice .nodeParams.channelKeyManager)
1314+ withFixture(Seq (1_010_000 sat, 10_000 sat), ChannelTypes .AnchorOutputsZeroFeeHtlcTx (), channelKeyManager_opt = Some (channelKeyManager)) { f =>
13311315 import f ._
13321316
13331317 val initialFeerate = FeeratePerKw (3_000 sat)
@@ -1355,6 +1339,11 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
13551339 assert(htlcSuccessTx2.txid == htlcSuccessTxId2)
13561340 assert(htlcSuccessTx1.fees < htlcSuccessTx2.fees)
13571341 assert(htlcSuccessInputs1 != htlcSuccessInputs2)
1342+
1343+ // check that wallet inputs were passed to the sign() methods
1344+ val publishedHtlcSuccessTx = getTransaction(probe, htlcSuccessTxId2)
1345+ assert(channelKeyManager.walletInputs.get() == getExtraInputsMap(probe, publishedHtlcSuccessTx))
1346+
13581347 val htlcSuccessTargetFee = Transactions .weight2fee(targetFeerate, htlcSuccessTx2.weight.toInt)
13591348 assert(htlcSuccessTargetFee * 0.9 <= htlcSuccessTx2.fees && htlcSuccessTx2.fees <= htlcSuccessTargetFee * 1.1 , s " actualFee= ${htlcSuccessTx2.fees} targetFee= $htlcSuccessTargetFee" )
13601349 }
@@ -1422,7 +1411,9 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
14221411 }
14231412
14241413 test(" htlc timeout tx not confirming, increasing fees" ) {
1425- withFixture(Seq (500 millibtc), ChannelTypes .AnchorOutputsZeroFeeHtlcTx ()) { f =>
1414+ val channelKeyManager = new DummyChannelKeyManager (TestConstants .Alice .channelKeyManager)
1415+
1416+ withFixture(Seq (500 millibtc), ChannelTypes .AnchorOutputsZeroFeeHtlcTx (), channelKeyManager_opt = Some (channelKeyManager)) { f =>
14261417 import f ._
14271418
14281419 val feerate = FeeratePerKw (15_000 sat)
@@ -1452,6 +1443,10 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
14521443 assert(htlcTimeoutTx2.txid == htlcTimeoutTxId2)
14531444 assert(htlcTimeoutTx1.fees < htlcTimeoutTx2.fees)
14541445 assert(htlcTimeoutInputs1 == htlcTimeoutInputs2)
1446+
1447+ val publishedHtlcTimeoutTx = getTransaction(probe, htlcTimeoutTxId2)
1448+ assert(channelKeyManager.walletInputs.get() == getExtraInputsMap(probe, publishedHtlcTimeoutTx))
1449+
14551450 // Once the confirmation target is reach, we should raise the feerate by at least 20% at every block.
14561451 val htlcTimeoutTargetFee = Transactions .weight2fee(feerate * 1.2 , htlcTimeoutTx2.weight.toInt)
14571452 assert(htlcTimeoutTargetFee * 0.9 <= htlcTimeoutTx2.fees && htlcTimeoutTx2.fees <= htlcTimeoutTargetFee * 1.1 , s " actualFee= ${htlcTimeoutTx2.fees} targetFee= $htlcTimeoutTargetFee" )
@@ -1922,4 +1917,33 @@ class ReplaceableTxPublisherWithEclairSignerSpec extends ReplaceableTxPublisherS
19221917
19231918 (walletRpcClient, walletClient)
19241919 }
1925- }
1920+ }
1921+
1922+ // wrapper that delegates operations to an actual ChannelKeyManager and extra inputs passed to the sign() methods
1923+ class DummyChannelKeyManager (channelKeyManager : ChannelKeyManager ) extends ChannelKeyManager {
1924+ val walletInputs = new AtomicReference [Map [OutPoint , TxOut ]](Map .empty)
1925+
1926+ // @formatter:off
1927+ override def fundingPublicKey (fundingKeyPath : DeterministicWallet .KeyPath , fundingTxIndex : Long ): DeterministicWallet .ExtendedPublicKey = channelKeyManager.fundingPublicKey(fundingKeyPath, fundingTxIndex)
1928+ override def revocationPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManager.revocationPoint(channelKeyPath)
1929+ override def paymentPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManager.paymentPoint(channelKeyPath)
1930+ override def delayedPaymentPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManager.delayedPaymentPoint(channelKeyPath)
1931+ override def htlcPoint (channelKeyPath : DeterministicWallet .KeyPath ): DeterministicWallet .ExtendedPublicKey = channelKeyManager.htlcPoint(channelKeyPath)
1932+ override def commitmentSecret (channelKeyPath : DeterministicWallet .KeyPath , index : Long ): Crypto .PrivateKey = channelKeyManager.commitmentSecret(channelKeyPath, index)
1933+ override def commitmentPoint (channelKeyPath : DeterministicWallet .KeyPath , index : Long ): PublicKey = channelKeyManager.commitmentPoint(channelKeyPath, index)
1934+ override def newFundingKeyPath (isChannelOpener : Boolean ): DeterministicWallet .KeyPath = channelKeyManager.newFundingKeyPath(isChannelOpener)
1935+ override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
1936+ walletInputs.set(extraUtxos)
1937+ channelKeyManager.sign(tx, publicKey, txOwner, commitmentFormat, extraUtxos)
1938+ }
1939+ override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , remotePoint : PublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
1940+ walletInputs.set(extraUtxos)
1941+ channelKeyManager.sign(tx, publicKey, remotePoint, txOwner, commitmentFormat, extraUtxos)
1942+ }
1943+ override def sign (tx : TransactionWithInputInfo , publicKey : DeterministicWallet .ExtendedPublicKey , remoteSecret : Crypto .PrivateKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat , extraUtxos : Map [OutPoint , TxOut ]): ByteVector64 = {
1944+ walletInputs.set(extraUtxos)
1945+ channelKeyManager.sign(tx, publicKey, remoteSecret, txOwner, commitmentFormat, extraUtxos)
1946+ }
1947+ override def signChannelAnnouncement (witness : ByteVector , fundingKeyPath : DeterministicWallet .KeyPath ): ByteVector64 = channelKeyManager.signChannelAnnouncement(witness, fundingKeyPath)
1948+ // @formatter:on
1949+ }
0 commit comments