mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-22 06:21:40 +01:00
Merge pull request #9195 from yyforyongyu/optimize-itest-setup
itest+lntest: speed up test setup
This commit is contained in:
commit
f46ae2f893
17 changed files with 134 additions and 102 deletions
|
@ -76,6 +76,10 @@
|
||||||
|
|
||||||
* Log rotation can now use ZSTD
|
* Log rotation can now use ZSTD
|
||||||
|
|
||||||
|
* [A new method](https://github.com/lightningnetwork/lnd/pull/9195)
|
||||||
|
`AssertTxnsNotInMempool` has been added to `lntest` package to allow batch
|
||||||
|
exclusion check in itest.
|
||||||
|
|
||||||
# Technical and Architectural Updates
|
# Technical and Architectural Updates
|
||||||
## BOLT Spec Updates
|
## BOLT Spec Updates
|
||||||
|
|
||||||
|
|
|
@ -634,7 +634,7 @@ func channelForceClosureTest(ht *lntest.HarnessTest,
|
||||||
// Recorf the HTLC outpoint, such that we can later
|
// Recorf the HTLC outpoint, such that we can later
|
||||||
// check whether it gets swept
|
// check whether it gets swept
|
||||||
op := wire.OutPoint{
|
op := wire.OutPoint{
|
||||||
Hash: *htlcTxID,
|
Hash: htlcTxID,
|
||||||
Index: uint32(i),
|
Index: uint32(i),
|
||||||
}
|
}
|
||||||
htlcTxOutpointSet[op] = 0
|
htlcTxOutpointSet[op] = 0
|
||||||
|
|
|
@ -117,7 +117,7 @@ func coopCloseWithHTLCs(ht *lntest.HarnessTest) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Wait for the close tx to be in the Mempool.
|
// Wait for the close tx to be in the Mempool.
|
||||||
ht.AssertTxInMempool(&closeTxid)
|
ht.AssertTxInMempool(closeTxid)
|
||||||
|
|
||||||
// Wait for it to get mined and finish tearing down.
|
// Wait for it to get mined and finish tearing down.
|
||||||
ht.AssertStreamChannelCoopClosed(alice, chanPoint, false, closeClient)
|
ht.AssertStreamChannelCoopClosed(alice, chanPoint, false, closeClient)
|
||||||
|
|
|
@ -874,7 +874,7 @@ func testChannelFundingPersistence(ht *lntest.HarnessTest) {
|
||||||
// channel has been opened. The funding transaction should be found
|
// channel has been opened. The funding transaction should be found
|
||||||
// within the newly mined block.
|
// within the newly mined block.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, fundingTxID)
|
ht.AssertTxInBlock(block, *fundingTxID)
|
||||||
|
|
||||||
// Get the height that our transaction confirmed at.
|
// Get the height that our transaction confirmed at.
|
||||||
height := int32(ht.CurrentHeight())
|
height := int32(ht.CurrentHeight())
|
||||||
|
@ -1067,13 +1067,13 @@ func testBatchChanFunding(ht *lntest.HarnessTest) {
|
||||||
|
|
||||||
// Mine the batch transaction and check the network topology.
|
// Mine the batch transaction and check the network topology.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, txHash)
|
ht.AssertTxInBlock(block, *txHash)
|
||||||
ht.AssertTopologyChannelOpen(alice, chanPoint1)
|
ht.AssertTopologyChannelOpen(alice, chanPoint1)
|
||||||
ht.AssertTopologyChannelOpen(alice, chanPoint2)
|
ht.AssertTopologyChannelOpen(alice, chanPoint2)
|
||||||
ht.AssertTopologyChannelOpen(alice, chanPoint3)
|
ht.AssertTopologyChannelOpen(alice, chanPoint3)
|
||||||
|
|
||||||
// Check if the change type from the batch_open_channel funding is P2TR.
|
// Check if the change type from the batch_open_channel funding is P2TR.
|
||||||
rawTx := ht.GetRawTransaction(txHash)
|
rawTx := ht.GetRawTransaction(*txHash)
|
||||||
require.Len(ht, rawTx.MsgTx().TxOut, 5)
|
require.Len(ht, rawTx.MsgTx().TxOut, 5)
|
||||||
|
|
||||||
// Check the fee rate of the batch-opening transaction. We expect slight
|
// Check the fee rate of the batch-opening transaction. We expect slight
|
||||||
|
|
|
@ -736,8 +736,8 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
||||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||||
blocksMined++
|
blocksMined++
|
||||||
|
|
||||||
htlcOutpoint := wire.OutPoint{Hash: *closeTx, Index: 2}
|
htlcOutpoint := wire.OutPoint{Hash: closeTx, Index: 2}
|
||||||
bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 3}
|
bobCommitOutpoint := wire.OutPoint{Hash: closeTx, Index: 3}
|
||||||
|
|
||||||
// Before the HTLC times out, we'll need to assert that Bob broadcasts
|
// Before the HTLC times out, we'll need to assert that Bob broadcasts
|
||||||
// a sweep transaction for his commit output. Note that if the channel
|
// a sweep transaction for his commit output. Note that if the channel
|
||||||
|
@ -761,7 +761,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
||||||
)
|
)
|
||||||
txid := commitSweepTx.TxHash()
|
txid := commitSweepTx.TxHash()
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txid)
|
ht.AssertTxInBlock(block, txid)
|
||||||
|
|
||||||
blocksMined++
|
blocksMined++
|
||||||
}
|
}
|
||||||
|
@ -789,7 +789,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
||||||
// Next, we'll mine an additional block. This should serve to confirm
|
// Next, we'll mine an additional block. This should serve to confirm
|
||||||
// the second layer timeout transaction.
|
// the second layer timeout transaction.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &timeoutTx)
|
ht.AssertTxInBlock(block, timeoutTx)
|
||||||
|
|
||||||
// With the second layer timeout transaction confirmed, Bob should have
|
// With the second layer timeout transaction confirmed, Bob should have
|
||||||
// canceled backwards the HTLC that carol sent.
|
// canceled backwards the HTLC that carol sent.
|
||||||
|
@ -1041,13 +1041,13 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
||||||
// Mine a block to trigger the sweep.
|
// Mine a block to trigger the sweep.
|
||||||
ht.MineEmptyBlocks(1)
|
ht.MineEmptyBlocks(1)
|
||||||
|
|
||||||
bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 3}
|
bobCommitOutpoint := wire.OutPoint{Hash: closeTx, Index: 3}
|
||||||
bobCommitSweep := ht.AssertOutpointInMempool(
|
bobCommitSweep := ht.AssertOutpointInMempool(
|
||||||
bobCommitOutpoint,
|
bobCommitOutpoint,
|
||||||
)
|
)
|
||||||
bobCommitSweepTxid := bobCommitSweep.TxHash()
|
bobCommitSweepTxid := bobCommitSweep.TxHash()
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &bobCommitSweepTxid)
|
ht.AssertTxInBlock(block, bobCommitSweepTxid)
|
||||||
}
|
}
|
||||||
ht.AssertNumPendingForceClose(bob, 0)
|
ht.AssertNumPendingForceClose(bob, 0)
|
||||||
|
|
||||||
|
@ -1226,7 +1226,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
||||||
|
|
||||||
// Mine a block that should confirm the commit tx.
|
// Mine a block that should confirm the commit tx.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &closingTxid)
|
ht.AssertTxInBlock(block, closingTxid)
|
||||||
|
|
||||||
// After the force close transaction is mined, Carol should offer her
|
// After the force close transaction is mined, Carol should offer her
|
||||||
// second-level success HTLC tx and anchor to the sweeper.
|
// second-level success HTLC tx and anchor to the sweeper.
|
||||||
|
@ -1303,7 +1303,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
||||||
bobSecondLvlTx := ht.GetNumTxsFromMempool(1)[0]
|
bobSecondLvlTx := ht.GetNumTxsFromMempool(1)[0]
|
||||||
|
|
||||||
// It should spend from the commitment in the channel with Alice.
|
// It should spend from the commitment in the channel with Alice.
|
||||||
ht.AssertTxSpendFrom(bobSecondLvlTx, *bobForceClose)
|
ht.AssertTxSpendFrom(bobSecondLvlTx, bobForceClose)
|
||||||
|
|
||||||
// At this point, Bob should have broadcast his second layer success
|
// At this point, Bob should have broadcast his second layer success
|
||||||
// transaction, and should have sent it to the nursery for incubation.
|
// transaction, and should have sent it to the nursery for incubation.
|
||||||
|
@ -1362,7 +1362,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
||||||
// Now Bob should have no pending channels anymore, as this just
|
// Now Bob should have no pending channels anymore, as this just
|
||||||
// resolved it by the confirmation of the sweep transaction.
|
// resolved it by the confirmation of the sweep transaction.
|
||||||
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &bobSweepTxid)
|
ht.AssertTxInBlock(block, bobSweepTxid)
|
||||||
|
|
||||||
// With the script-enforced lease commitment type, Alice and Bob still
|
// With the script-enforced lease commitment type, Alice and Bob still
|
||||||
// haven't been able to sweep their respective commit outputs due to the
|
// haven't been able to sweep their respective commit outputs due to the
|
||||||
|
@ -1397,7 +1397,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
||||||
|
|
||||||
// Both Alice and Bob show broadcast their commit sweeps.
|
// Both Alice and Bob show broadcast their commit sweeps.
|
||||||
aliceCommitOutpoint := wire.OutPoint{
|
aliceCommitOutpoint := wire.OutPoint{
|
||||||
Hash: *bobForceClose, Index: 3,
|
Hash: bobForceClose, Index: 3,
|
||||||
}
|
}
|
||||||
ht.AssertOutpointInMempool(
|
ht.AssertOutpointInMempool(
|
||||||
aliceCommitOutpoint,
|
aliceCommitOutpoint,
|
||||||
|
@ -1574,7 +1574,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
||||||
|
|
||||||
// Mine a block, which should contain: the commitment.
|
// Mine a block, which should contain: the commitment.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &closingTxid)
|
ht.AssertTxInBlock(block, closingTxid)
|
||||||
|
|
||||||
// After the force close transaction is mined, Carol should offer her
|
// After the force close transaction is mined, Carol should offer her
|
||||||
// second level HTLC tx to the sweeper, along with her anchor output.
|
// second level HTLC tx to the sweeper, along with her anchor output.
|
||||||
|
@ -1628,12 +1628,12 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
||||||
bobHtlcSweepTxid := bobHtlcSweep.TxHash()
|
bobHtlcSweepTxid := bobHtlcSweep.TxHash()
|
||||||
|
|
||||||
// It should spend from the commitment in the channel with Alice.
|
// It should spend from the commitment in the channel with Alice.
|
||||||
ht.AssertTxSpendFrom(bobHtlcSweep, *aliceForceClose)
|
ht.AssertTxSpendFrom(bobHtlcSweep, aliceForceClose)
|
||||||
|
|
||||||
// We'll now mine a block which should confirm Bob's HTLC sweep
|
// We'll now mine a block which should confirm Bob's HTLC sweep
|
||||||
// transaction.
|
// transaction.
|
||||||
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &bobHtlcSweepTxid)
|
ht.AssertTxInBlock(block, bobHtlcSweepTxid)
|
||||||
carolSecondLevelCSV--
|
carolSecondLevelCSV--
|
||||||
|
|
||||||
// Now that the sweeping transaction has been confirmed, Bob should now
|
// Now that the sweeping transaction has been confirmed, Bob should now
|
||||||
|
@ -1690,7 +1690,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
||||||
|
|
||||||
// Both Alice and Bob should broadcast their commit sweeps.
|
// Both Alice and Bob should broadcast their commit sweeps.
|
||||||
aliceCommitOutpoint := wire.OutPoint{
|
aliceCommitOutpoint := wire.OutPoint{
|
||||||
Hash: *aliceForceClose, Index: 3,
|
Hash: aliceForceClose, Index: 3,
|
||||||
}
|
}
|
||||||
ht.AssertOutpointInMempool(aliceCommitOutpoint)
|
ht.AssertOutpointInMempool(aliceCommitOutpoint)
|
||||||
bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3}
|
bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3}
|
||||||
|
@ -2145,7 +2145,7 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
||||||
// level sweep. Now Bob should have no pending channels anymore, as
|
// level sweep. Now Bob should have no pending channels anymore, as
|
||||||
// this just resolved it by the confirmation of the sweep transaction.
|
// this just resolved it by the confirmation of the sweep transaction.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, numExpected)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, numExpected)[0]
|
||||||
ht.AssertTxInBlock(block, &bobSweep)
|
ht.AssertTxInBlock(block, bobSweep)
|
||||||
|
|
||||||
// For leased channels, we need to mine one more block to confirm Bob's
|
// For leased channels, we need to mine one more block to confirm Bob's
|
||||||
// commit output sweep.
|
// commit output sweep.
|
||||||
|
|
|
@ -111,7 +111,7 @@ func testNonStdSweepInner(ht *lntest.HarnessTest, address string) {
|
||||||
for _, inp := range msgTx.TxIn {
|
for _, inp := range msgTx.TxIn {
|
||||||
// Fetch the previous outpoint's value.
|
// Fetch the previous outpoint's value.
|
||||||
prevOut := inp.PreviousOutPoint
|
prevOut := inp.PreviousOutPoint
|
||||||
ptx := ht.GetRawTransaction(&prevOut.Hash)
|
ptx := ht.GetRawTransaction(prevOut.Hash)
|
||||||
|
|
||||||
pout := ptx.MsgTx().TxOut[prevOut.Index]
|
pout := ptx.MsgTx().TxOut[prevOut.Index]
|
||||||
inputVal += int(pout.Value)
|
inputVal += int(pout.Value)
|
||||||
|
|
|
@ -60,7 +60,7 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) {
|
||||||
// channel on the original miner's chain, which should be considered
|
// channel on the original miner's chain, which should be considered
|
||||||
// open.
|
// open.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(10, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(10, 1)[0]
|
||||||
ht.AssertTxInBlock(block, fundingTxID)
|
ht.AssertTxInBlock(block, *fundingTxID)
|
||||||
_, err = tempMiner.Client.Generate(15)
|
_, err = tempMiner.Client.Generate(15)
|
||||||
require.NoError(ht, err, "unable to generate blocks")
|
require.NoError(ht, err, "unable to generate blocks")
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) {
|
||||||
|
|
||||||
// Cleanup by mining the funding tx again, then closing the channel.
|
// Cleanup by mining the funding tx again, then closing the channel.
|
||||||
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, fundingTxID)
|
ht.AssertTxInBlock(block, *fundingTxID)
|
||||||
|
|
||||||
ht.CloseChannel(alice, chanPoint)
|
ht.CloseChannel(alice, chanPoint)
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode,
|
||||||
|
|
||||||
txHash := finalTx.TxHash()
|
txHash := finalTx.TxHash()
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
||||||
ht.AssertTopologyChannelOpen(carol, chanPoint2)
|
ht.AssertTopologyChannelOpen(carol, chanPoint2)
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol,
|
||||||
// Now we can mine a block to get the transaction confirmed, then wait
|
// Now we can mine a block to get the transaction confirmed, then wait
|
||||||
// for the new channel to be propagated through the network.
|
// for the new channel to be propagated through the network.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
||||||
ht.AssertTopologyChannelOpen(carol, chanPoint2)
|
ht.AssertTopologyChannelOpen(carol, chanPoint2)
|
||||||
|
|
||||||
|
@ -638,7 +638,7 @@ func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, carol,
|
||||||
|
|
||||||
txHash := finalTx.TxHash()
|
txHash := finalTx.TxHash()
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
ht.AssertTopologyChannelOpen(carol, chanPoint)
|
||||||
|
|
||||||
// Next, to make sure the channel functions as normal, we'll make some
|
// Next, to make sure the channel functions as normal, we'll make some
|
||||||
|
@ -1337,7 +1337,7 @@ func extractPublishAndMine(ht *lntest.HarnessTest, node *node.HarnessNode,
|
||||||
// Mine one block which should contain two transactions.
|
// Mine one block which should contain two transactions.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
txHash := finalTx.TxHash()
|
txHash := finalTx.TxHash()
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
|
|
||||||
return finalTx
|
return finalTx
|
||||||
}
|
}
|
||||||
|
@ -1443,8 +1443,8 @@ func assertPsbtSpend(ht *lntest.HarnessTest, alice *node.HarnessNode,
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 2)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 2)[0]
|
||||||
firstTxHash := prevTx.TxHash()
|
firstTxHash := prevTx.TxHash()
|
||||||
secondTxHash := finalTx.TxHash()
|
secondTxHash := finalTx.TxHash()
|
||||||
ht.AssertTxInBlock(block, &firstTxHash)
|
ht.AssertTxInBlock(block, firstTxHash)
|
||||||
ht.AssertTxInBlock(block, &secondTxHash)
|
ht.AssertTxInBlock(block, secondTxHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// assertPsbtFundSignSpend funds a PSBT from the internal wallet and then
|
// assertPsbtFundSignSpend funds a PSBT from the internal wallet and then
|
||||||
|
@ -1807,7 +1807,7 @@ func testPsbtChanFundingWithUnstableUtxos(ht *lntest.HarnessTest) {
|
||||||
|
|
||||||
txHash := finalTx.TxHash()
|
txHash := finalTx.TxHash()
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
|
|
||||||
// Now we do the same but instead use preselected utxos to verify that
|
// Now we do the same but instead use preselected utxos to verify that
|
||||||
// these utxos respects the utxo restrictions on sweeper unconfirmed
|
// these utxos respects the utxo restrictions on sweeper unconfirmed
|
||||||
|
@ -1951,5 +1951,5 @@ func testPsbtChanFundingWithUnstableUtxos(ht *lntest.HarnessTest) {
|
||||||
|
|
||||||
txHash = finalTx.TxHash()
|
txHash = finalTx.TxHash()
|
||||||
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
ht.AssertTxInBlock(block, &txHash)
|
ht.AssertTxInBlock(block, txHash)
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ func breachRetributionTestCase(ht *lntest.HarnessTest,
|
||||||
// ordering, the first output in this breach tx is the to_remote
|
// ordering, the first output in this breach tx is the to_remote
|
||||||
// output.
|
// output.
|
||||||
toRemoteOp := wire.OutPoint{
|
toRemoteOp := wire.OutPoint{
|
||||||
Hash: *breachTXID,
|
Hash: breachTXID,
|
||||||
Index: 0,
|
Index: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ func breachRetributionTestCase(ht *lntest.HarnessTest,
|
||||||
// Assert that all the inputs of this transaction are spending outputs
|
// Assert that all the inputs of this transaction are spending outputs
|
||||||
// generated by Bob's breach transaction above.
|
// generated by Bob's breach transaction above.
|
||||||
for _, txIn := range justiceTx.TxIn {
|
for _, txIn := range justiceTx.TxIn {
|
||||||
require.Equal(ht, *breachTXID, txIn.PreviousOutPoint.Hash,
|
require.Equal(ht, breachTXID, txIn.PreviousOutPoint.Hash,
|
||||||
"justice tx not spending commitment utxo")
|
"justice tx not spending commitment utxo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ func breachRetributionTestCase(ht *lntest.HarnessTest,
|
||||||
// transaction which was just accepted into the mempool.
|
// transaction which was just accepted into the mempool.
|
||||||
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
justiceTxid := justiceTx.TxHash()
|
justiceTxid := justiceTx.TxHash()
|
||||||
ht.AssertTxInBlock(block, &justiceTxid)
|
ht.AssertTxInBlock(block, justiceTxid)
|
||||||
|
|
||||||
ht.AssertNodeNumChannels(carol, 0)
|
ht.AssertNodeNumChannels(carol, 0)
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest,
|
||||||
// ordering, the first output in this breach tx is the to_local
|
// ordering, the first output in this breach tx is the to_local
|
||||||
// output.
|
// output.
|
||||||
toLocalOp := wire.OutPoint{
|
toLocalOp := wire.OutPoint{
|
||||||
Hash: *breachTXID,
|
Hash: breachTXID,
|
||||||
Index: 0,
|
Index: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest,
|
||||||
// transaction which was just accepted into the mempool.
|
// transaction which was just accepted into the mempool.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
justiceTxid := justiceTx.TxHash()
|
justiceTxid := justiceTx.TxHash()
|
||||||
ht.AssertTxInBlock(block, &justiceTxid)
|
ht.AssertTxInBlock(block, justiceTxid)
|
||||||
|
|
||||||
// At this point, Dave should have no pending channels.
|
// At this point, Dave should have no pending channels.
|
||||||
ht.AssertNodeNumChannels(dave, 0)
|
ht.AssertNodeNumChannels(dave, 0)
|
||||||
|
@ -567,7 +567,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
// outputs to the second level before Dave broadcasts his justice tx,
|
// outputs to the second level before Dave broadcasts his justice tx,
|
||||||
// we'll search through the mempool for a tx that matches the number of
|
// we'll search through the mempool for a tx that matches the number of
|
||||||
// expected inputs in the justice tx.
|
// expected inputs in the justice tx.
|
||||||
var justiceTxid *chainhash.Hash
|
var justiceTxid chainhash.Hash
|
||||||
errNotFound := errors.New("justice tx not found")
|
errNotFound := errors.New("justice tx not found")
|
||||||
findJusticeTx := func() (*chainhash.Hash, error) {
|
findJusticeTx := func() (*chainhash.Hash, error) {
|
||||||
mempool := ht.GetRawMempool()
|
mempool := ht.GetRawMempool()
|
||||||
|
@ -579,14 +579,14 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
// NOTE: We don't use `ht.GetRawTransaction`
|
// NOTE: We don't use `ht.GetRawTransaction`
|
||||||
// which asserts a txid must be found as the HTLC
|
// which asserts a txid must be found as the HTLC
|
||||||
// spending txes might be aggregated.
|
// spending txes might be aggregated.
|
||||||
tx, err := ht.Miner().Client.GetRawTransaction(txid)
|
tx, err := ht.Miner().Client.GetRawTransaction(&txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
exNumInputs := 2 + numInvoices
|
exNumInputs := 2 + numInvoices
|
||||||
if len(tx.MsgTx().TxIn) == exNumInputs {
|
if len(tx.MsgTx().TxIn) == exNumInputs {
|
||||||
return txid, nil
|
return &txid, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +598,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
justiceTxid = txid
|
justiceTxid = *txid
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, defaultTimeout)
|
}, defaultTimeout)
|
||||||
|
@ -619,7 +619,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
justiceTxid = txid
|
justiceTxid = *txid
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, defaultTimeout)
|
}, defaultTimeout)
|
||||||
|
@ -631,7 +631,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
// isSecondLevelSpend checks that the passed secondLevelTxid is a
|
// isSecondLevelSpend checks that the passed secondLevelTxid is a
|
||||||
// potentitial second level spend spending from the commit tx.
|
// potentitial second level spend spending from the commit tx.
|
||||||
isSecondLevelSpend := func(commitTxid,
|
isSecondLevelSpend := func(commitTxid,
|
||||||
secondLevelTxid *chainhash.Hash) bool {
|
secondLevelTxid chainhash.Hash) bool {
|
||||||
|
|
||||||
secondLevel := ht.GetRawTransaction(secondLevelTxid)
|
secondLevel := ht.GetRawTransaction(secondLevelTxid)
|
||||||
|
|
||||||
|
@ -661,7 +661,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest,
|
||||||
// the breach tx, Carol might have had the time to take an
|
// the breach tx, Carol might have had the time to take an
|
||||||
// output to the second level. In that case, check that the
|
// output to the second level. In that case, check that the
|
||||||
// justice tx is spending this second level output.
|
// justice tx is spending this second level output.
|
||||||
if isSecondLevelSpend(breachTXID, &txIn.PreviousOutPoint.Hash) {
|
if isSecondLevelSpend(breachTXID, txIn.PreviousOutPoint.Hash) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
require.Fail(ht, "justice tx not spending commitment utxo "+
|
require.Fail(ht, "justice tx not spending commitment utxo "+
|
||||||
|
|
|
@ -318,7 +318,7 @@ func assertSignOutputRaw(ht *lntest.HarnessTest,
|
||||||
tx := wire.NewMsgTx(2)
|
tx := wire.NewMsgTx(2)
|
||||||
tx.TxIn = []*wire.TxIn{{
|
tx.TxIn = []*wire.TxIn{{
|
||||||
PreviousOutPoint: wire.OutPoint{
|
PreviousOutPoint: wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: txid,
|
||||||
Index: uint32(targetOutputIndex),
|
Index: uint32(targetOutputIndex),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -214,7 +214,7 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns := ht.GetNumTxsFromMempool(2)
|
txns := ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx := ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx := ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Get the weight for Bob's anchor sweeping tx.
|
// Get the weight for Bob's anchor sweeping tx.
|
||||||
txWeight := ht.CalculateTxWeight(sweepTx)
|
txWeight := ht.CalculateTxWeight(sweepTx)
|
||||||
|
@ -281,7 +281,7 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx = ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx = ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Calculate the fee rate of Bob's new sweeping tx.
|
// Calculate the fee rate of Bob's new sweeping tx.
|
||||||
feeRate = uint64(ht.CalculateTxFeeRate(sweepTx))
|
feeRate = uint64(ht.CalculateTxFeeRate(sweepTx))
|
||||||
|
@ -320,7 +320,7 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx = ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx = ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Calculate the fee of Bob's new sweeping tx.
|
// Calculate the fee of Bob's new sweeping tx.
|
||||||
fee = uint64(ht.CalculateTxFee(sweepTx))
|
fee = uint64(ht.CalculateTxFee(sweepTx))
|
||||||
|
@ -341,7 +341,7 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
currentSweepTx := ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
currentSweepTx := ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Assert the anchor sweep tx stays unchanged.
|
// Assert the anchor sweep tx stays unchanged.
|
||||||
require.Equal(ht, sweepTx.TxHash(), currentSweepTx.TxHash())
|
require.Equal(ht, sweepTx.TxHash(), currentSweepTx.TxHash())
|
||||||
|
@ -553,7 +553,7 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns := ht.GetNumTxsFromMempool(2)
|
txns := ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx := ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx := ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Get the weight for Bob's anchor sweeping tx.
|
// Get the weight for Bob's anchor sweeping tx.
|
||||||
txWeight := ht.CalculateTxWeight(sweepTx)
|
txWeight := ht.CalculateTxWeight(sweepTx)
|
||||||
|
@ -620,7 +620,7 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx = ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx = ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Calculate the fee rate of Bob's new sweeping tx.
|
// Calculate the fee rate of Bob's new sweeping tx.
|
||||||
feeRate = uint64(ht.CalculateTxFeeRate(sweepTx))
|
feeRate = uint64(ht.CalculateTxFeeRate(sweepTx))
|
||||||
|
@ -659,7 +659,7 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
sweepTx = ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
sweepTx = ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Calculate the fee of Bob's new sweeping tx.
|
// Calculate the fee of Bob's new sweeping tx.
|
||||||
fee = uint64(ht.CalculateTxFee(sweepTx))
|
fee = uint64(ht.CalculateTxFee(sweepTx))
|
||||||
|
@ -680,7 +680,7 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) {
|
||||||
txns = ht.GetNumTxsFromMempool(2)
|
txns = ht.GetNumTxsFromMempool(2)
|
||||||
|
|
||||||
// Find the sweeping tx.
|
// Find the sweeping tx.
|
||||||
currentSweepTx := ht.FindSweepingTxns(txns, 1, *closeTxid)[0]
|
currentSweepTx := ht.FindSweepingTxns(txns, 1, closeTxid)[0]
|
||||||
|
|
||||||
// Assert the anchor sweep tx stays unchanged.
|
// Assert the anchor sweep tx stays unchanged.
|
||||||
require.Equal(ht, sweepTx.TxHash(), currentSweepTx.TxHash())
|
require.Equal(ht, sweepTx.TxHash(), currentSweepTx.TxHash())
|
||||||
|
@ -2274,7 +2274,7 @@ func testBumpForceCloseFee(ht *lntest.HarnessTest) {
|
||||||
// this anchor sweep transaction (because of the small fee delta).
|
// this anchor sweep transaction (because of the small fee delta).
|
||||||
ht.MineEmptyBlocks(1)
|
ht.MineEmptyBlocks(1)
|
||||||
cpfpHash1 := cpfpSweep1.TxHash()
|
cpfpHash1 := cpfpSweep1.TxHash()
|
||||||
ht.AssertTxInMempool(&cpfpHash1)
|
ht.AssertTxInMempool(cpfpHash1)
|
||||||
|
|
||||||
// Now Bump the fee rate again with a bigger starting fee rate of the
|
// Now Bump the fee rate again with a bigger starting fee rate of the
|
||||||
// fee function.
|
// fee function.
|
||||||
|
|
|
@ -171,7 +171,7 @@ func testTaprootComputeInputScriptKeySpendBip86(ht *lntest.HarnessTest,
|
||||||
ht.AssertUTXOInWallet(alice, op, "")
|
ht.AssertUTXOInWallet(alice, op, "")
|
||||||
|
|
||||||
p2trOutpoint := wire.OutPoint{
|
p2trOutpoint := wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: txid,
|
||||||
Index: uint32(p2trOutputIndex),
|
Index: uint32(p2trOutputIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1413,7 +1413,7 @@ func clearWalletImportedTapscriptBalance(ht *lntest.HarnessTest,
|
||||||
// Mine one block which should contain the sweep transaction.
|
// Mine one block which should contain the sweep transaction.
|
||||||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
sweepTxHash := sweepTx.TxHash()
|
sweepTxHash := sweepTx.TxHash()
|
||||||
ht.AssertTxInBlock(block, &sweepTxHash)
|
ht.AssertTxInBlock(block, sweepTxHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// testScriptHashLock returns a simple bitcoin script that locks the funds to
|
// testScriptHashLock returns a simple bitcoin script that locks the funds to
|
||||||
|
@ -1484,7 +1484,7 @@ func sendToTaprootOutput(ht *lntest.HarnessTest, hn *node.HarnessNode,
|
||||||
txid := ht.AssertNumTxsInMempool(1)[0]
|
txid := ht.AssertNumTxsInMempool(1)[0]
|
||||||
p2trOutputIndex := ht.GetOutputIndex(txid, tapScriptAddr.String())
|
p2trOutputIndex := ht.GetOutputIndex(txid, tapScriptAddr.String())
|
||||||
p2trOutpoint := wire.OutPoint{
|
p2trOutpoint := wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: txid,
|
||||||
Index: uint32(p2trOutputIndex),
|
Index: uint32(p2trOutputIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1849,7 +1849,7 @@ func testTaprootCoopClose(ht *lntest.HarnessTest) {
|
||||||
|
|
||||||
// assertTaprootDeliveryUsed returns true if a Taproot addr was used in
|
// assertTaprootDeliveryUsed returns true if a Taproot addr was used in
|
||||||
// the co-op close transaction.
|
// the co-op close transaction.
|
||||||
assertTaprootDeliveryUsed := func(closingTxid *chainhash.Hash) bool {
|
assertTaprootDeliveryUsed := func(closingTxid chainhash.Hash) bool {
|
||||||
tx := ht.GetRawTransaction(closingTxid)
|
tx := ht.GetRawTransaction(closingTxid)
|
||||||
for _, txOut := range tx.MsgTx().TxOut {
|
for _, txOut := range tx.MsgTx().TxOut {
|
||||||
if !txscript.IsPayToTaproot(txOut.PkScript) {
|
if !txscript.IsPayToTaproot(txOut.PkScript) {
|
||||||
|
|
|
@ -372,7 +372,7 @@ func fundChanAndCloseFromImportedAccount(ht *lntest.HarnessTest, srcNode,
|
||||||
)
|
)
|
||||||
|
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, txHash)
|
ht.AssertTxInBlock(block, *txHash)
|
||||||
|
|
||||||
confBalanceAfterChan += chanChangeUtxoAmt
|
confBalanceAfterChan += chanChangeUtxoAmt
|
||||||
ht.AssertWalletAccountBalance(srcNode, account, 0, 0)
|
ht.AssertWalletAccountBalance(srcNode, account, 0, 0)
|
||||||
|
@ -389,7 +389,7 @@ func fundChanAndCloseFromImportedAccount(ht *lntest.HarnessTest, srcNode,
|
||||||
)
|
)
|
||||||
|
|
||||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||||
ht.AssertTxInBlock(block, txHash)
|
ht.AssertTxInBlock(block, *txHash)
|
||||||
|
|
||||||
confBalanceAfterChan += chanChangeUtxoAmt
|
confBalanceAfterChan += chanChangeUtxoAmt
|
||||||
ht.AssertWalletAccountBalance(
|
ht.AssertWalletAccountBalance(
|
||||||
|
|
|
@ -342,6 +342,7 @@ func (h *HarnessTest) SetupStandbyNodes() {
|
||||||
// above a good number of confirmations.
|
// above a good number of confirmations.
|
||||||
const totalTxes = 200
|
const totalTxes = 200
|
||||||
h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes)
|
h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes)
|
||||||
|
h.MineBlocks(numBlocksSendOutput)
|
||||||
|
|
||||||
// Now we want to wait for the nodes to catch up.
|
// Now we want to wait for the nodes to catch up.
|
||||||
h.WaitForBlockchainSync(h.Alice)
|
h.WaitForBlockchainSync(h.Alice)
|
||||||
|
@ -913,12 +914,12 @@ func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) error {
|
||||||
// GetChanPointFundingTxid takes a channel point and converts it into a chain
|
// GetChanPointFundingTxid takes a channel point and converts it into a chain
|
||||||
// hash.
|
// hash.
|
||||||
func (h *HarnessTest) GetChanPointFundingTxid(
|
func (h *HarnessTest) GetChanPointFundingTxid(
|
||||||
cp *lnrpc.ChannelPoint) *chainhash.Hash {
|
cp *lnrpc.ChannelPoint) chainhash.Hash {
|
||||||
|
|
||||||
txid, err := lnrpc.GetChanPointFundingTxid(cp)
|
txid, err := lnrpc.GetChanPointFundingTxid(cp)
|
||||||
require.NoError(h, err, "unable to get txid")
|
require.NoError(h, err, "unable to get txid")
|
||||||
|
|
||||||
return txid
|
return *txid
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutPointFromChannelPoint creates an outpoint from a given channel point.
|
// OutPointFromChannelPoint creates an outpoint from a given channel point.
|
||||||
|
@ -927,7 +928,7 @@ func (h *HarnessTest) OutPointFromChannelPoint(
|
||||||
|
|
||||||
txid := h.GetChanPointFundingTxid(cp)
|
txid := h.GetChanPointFundingTxid(cp)
|
||||||
return wire.OutPoint{
|
return wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: txid,
|
||||||
Index: cp.OutputIndex,
|
Index: cp.OutputIndex,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1263,7 +1264,7 @@ func (h *HarnessTest) OpenChannelAssertErr(srcNode, destNode *node.HarnessNode,
|
||||||
// mempool.
|
// mempool.
|
||||||
func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
|
func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint,
|
cp *lnrpc.ChannelPoint,
|
||||||
force bool) (rpc.CloseChanClient, *chainhash.Hash) {
|
force bool) (rpc.CloseChanClient, chainhash.Hash) {
|
||||||
|
|
||||||
// Calls the rpc to close the channel.
|
// Calls the rpc to close the channel.
|
||||||
closeReq := &lnrpc.CloseChannelRequest{
|
closeReq := &lnrpc.CloseChannelRequest{
|
||||||
|
@ -1306,9 +1307,9 @@ func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
|
||||||
pendingClose.ClosePending.Txid)
|
pendingClose.ClosePending.Txid)
|
||||||
|
|
||||||
// Assert the closing tx is in the mempool.
|
// Assert the closing tx is in the mempool.
|
||||||
h.miner.AssertTxInMempool(closeTxid)
|
h.miner.AssertTxInMempool(*closeTxid)
|
||||||
|
|
||||||
return stream, closeTxid
|
return stream, *closeTxid
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseChannel attempts to coop close a non-anchored channel identified by the
|
// CloseChannel attempts to coop close a non-anchored channel identified by the
|
||||||
|
@ -1321,7 +1322,7 @@ func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
|
||||||
// 5. the node reports zero waiting close channels.
|
// 5. the node reports zero waiting close channels.
|
||||||
// 6. the node receives a topology update regarding the channel close.
|
// 6. the node receives a topology update regarding the channel close.
|
||||||
func (h *HarnessTest) CloseChannel(hn *node.HarnessNode,
|
func (h *HarnessTest) CloseChannel(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint) *chainhash.Hash {
|
cp *lnrpc.ChannelPoint) chainhash.Hash {
|
||||||
|
|
||||||
stream, _ := h.CloseChannelAssertPending(hn, cp, false)
|
stream, _ := h.CloseChannelAssertPending(hn, cp, false)
|
||||||
|
|
||||||
|
@ -1340,7 +1341,7 @@ func (h *HarnessTest) CloseChannel(hn *node.HarnessNode,
|
||||||
// 7. mine DefaultCSV-1 blocks.
|
// 7. mine DefaultCSV-1 blocks.
|
||||||
// 8. the node reports zero pending force close channels.
|
// 8. the node reports zero pending force close channels.
|
||||||
func (h *HarnessTest) ForceCloseChannel(hn *node.HarnessNode,
|
func (h *HarnessTest) ForceCloseChannel(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint) *chainhash.Hash {
|
cp *lnrpc.ChannelPoint) chainhash.Hash {
|
||||||
|
|
||||||
stream, _ := h.CloseChannelAssertPending(hn, cp, true)
|
stream, _ := h.CloseChannelAssertPending(hn, cp, true)
|
||||||
|
|
||||||
|
@ -1902,7 +1903,7 @@ func (h *HarnessTest) CalculateTxFee(tx *wire.MsgTx) btcutil.Amount {
|
||||||
var balance btcutil.Amount
|
var balance btcutil.Amount
|
||||||
for _, in := range tx.TxIn {
|
for _, in := range tx.TxIn {
|
||||||
parentHash := in.PreviousOutPoint.Hash
|
parentHash := in.PreviousOutPoint.Hash
|
||||||
rawTx := h.miner.GetRawTransaction(&parentHash)
|
rawTx := h.miner.GetRawTransaction(parentHash)
|
||||||
parent := rawTx.MsgTx()
|
parent := rawTx.MsgTx()
|
||||||
value := parent.TxOut[in.PreviousOutPoint.Index].Value
|
value := parent.TxOut[in.PreviousOutPoint.Index].Value
|
||||||
|
|
||||||
|
@ -2151,7 +2152,7 @@ func (h *HarnessTest) ReceiveChannelEvent(
|
||||||
|
|
||||||
// GetOutputIndex returns the output index of the given address in the given
|
// GetOutputIndex returns the output index of the given address in the given
|
||||||
// transaction.
|
// transaction.
|
||||||
func (h *HarnessTest) GetOutputIndex(txid *chainhash.Hash, addr string) int {
|
func (h *HarnessTest) GetOutputIndex(txid chainhash.Hash, addr string) int {
|
||||||
// We'll then extract the raw transaction from the mempool in order to
|
// We'll then extract the raw transaction from the mempool in order to
|
||||||
// determine the index of the p2tr output.
|
// determine the index of the p2tr output.
|
||||||
tx := h.miner.GetRawTransaction(txid)
|
tx := h.miner.GetRawTransaction(txid)
|
||||||
|
|
|
@ -534,7 +534,7 @@ func (h *HarnessTest) AssertTopologyChannelClosed(hn *node.HarnessNode,
|
||||||
// by consuming a message from the passed close channel stream. Returns the
|
// by consuming a message from the passed close channel stream. Returns the
|
||||||
// closing txid if found.
|
// closing txid if found.
|
||||||
func (h HarnessTest) WaitForChannelCloseEvent(
|
func (h HarnessTest) WaitForChannelCloseEvent(
|
||||||
stream rpc.CloseChanClient) *chainhash.Hash {
|
stream rpc.CloseChanClient) chainhash.Hash {
|
||||||
|
|
||||||
// Consume one event.
|
// Consume one event.
|
||||||
event, err := h.ReceiveCloseChannelUpdate(stream)
|
event, err := h.ReceiveCloseChannelUpdate(stream)
|
||||||
|
@ -548,7 +548,7 @@ func (h HarnessTest) WaitForChannelCloseEvent(
|
||||||
require.NoErrorf(h, err, "wrong format found in closing txid: %v",
|
require.NoErrorf(h, err, "wrong format found in closing txid: %v",
|
||||||
resp.ChanClose.ClosingTxid)
|
resp.ChanClose.ClosingTxid)
|
||||||
|
|
||||||
return txid
|
return *txid
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertNumWaitingClose checks that a PendingChannels response from the node
|
// AssertNumWaitingClose checks that a PendingChannels response from the node
|
||||||
|
@ -634,7 +634,7 @@ func (h *HarnessTest) AssertNumPendingForceClose(hn *node.HarnessNode,
|
||||||
// - assert the node has seen the channel close update.
|
// - assert the node has seen the channel close update.
|
||||||
func (h *HarnessTest) AssertStreamChannelCoopClosed(hn *node.HarnessNode,
|
func (h *HarnessTest) AssertStreamChannelCoopClosed(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint, anchors bool,
|
cp *lnrpc.ChannelPoint, anchors bool,
|
||||||
stream rpc.CloseChanClient) *chainhash.Hash {
|
stream rpc.CloseChanClient) chainhash.Hash {
|
||||||
|
|
||||||
// Assert the channel is waiting close.
|
// Assert the channel is waiting close.
|
||||||
resp := h.AssertChannelWaitingClose(hn, cp)
|
resp := h.AssertChannelWaitingClose(hn, cp)
|
||||||
|
@ -682,7 +682,7 @@ func (h *HarnessTest) AssertStreamChannelCoopClosed(hn *node.HarnessNode,
|
||||||
// confirmed.
|
// confirmed.
|
||||||
func (h *HarnessTest) AssertStreamChannelForceClosed(hn *node.HarnessNode,
|
func (h *HarnessTest) AssertStreamChannelForceClosed(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint, anchorSweep bool,
|
cp *lnrpc.ChannelPoint, anchorSweep bool,
|
||||||
stream rpc.CloseChanClient) *chainhash.Hash {
|
stream rpc.CloseChanClient) chainhash.Hash {
|
||||||
|
|
||||||
// Assert the channel is waiting close.
|
// Assert the channel is waiting close.
|
||||||
resp := h.AssertChannelWaitingClose(hn, cp)
|
resp := h.AssertChannelWaitingClose(hn, cp)
|
||||||
|
|
|
@ -112,9 +112,7 @@ func (h *HarnessTest) MineBlocksAndAssertNumTxes(num uint32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the mempool has been updated.
|
// Make sure the mempool has been updated.
|
||||||
for _, txid := range txids {
|
h.miner.AssertTxnsNotInMempool(txids)
|
||||||
h.miner.AssertTxNotInMempool(*txid)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, make sure all the active nodes are synced.
|
// Finally, make sure all the active nodes are synced.
|
||||||
bestBlock := blocks[len(blocks)-1]
|
bestBlock := blocks[len(blocks)-1]
|
||||||
|
@ -202,7 +200,7 @@ func (h *HarnessTest) mineTillForceCloseResolved(hn *node.HarnessNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertTxInMempool asserts a given transaction can be found in the mempool.
|
// AssertTxInMempool asserts a given transaction can be found in the mempool.
|
||||||
func (h *HarnessTest) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
func (h *HarnessTest) AssertTxInMempool(txid chainhash.Hash) *wire.MsgTx {
|
||||||
return h.miner.AssertTxInMempool(txid)
|
return h.miner.AssertTxInMempool(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,14 +210,14 @@ func (h *HarnessTest) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
||||||
// NOTE: this should be used after `AssertTxInMempool` to ensure the tx has
|
// NOTE: this should be used after `AssertTxInMempool` to ensure the tx has
|
||||||
// entered the mempool before. Otherwise it might give false positive and the
|
// entered the mempool before. Otherwise it might give false positive and the
|
||||||
// tx may enter the mempool after the check.
|
// tx may enter the mempool after the check.
|
||||||
func (h *HarnessTest) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx {
|
func (h *HarnessTest) AssertTxNotInMempool(txid chainhash.Hash) {
|
||||||
return h.miner.AssertTxNotInMempool(txid)
|
h.miner.AssertTxNotInMempool(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertNumTxsInMempool polls until finding the desired number of transactions
|
// AssertNumTxsInMempool polls until finding the desired number of transactions
|
||||||
// in the provided miner's mempool. It will assert if this number is not met
|
// in the provided miner's mempool. It will assert if this number is not met
|
||||||
// after the given timeout.
|
// after the given timeout.
|
||||||
func (h *HarnessTest) AssertNumTxsInMempool(n int) []*chainhash.Hash {
|
func (h *HarnessTest) AssertNumTxsInMempool(n int) []chainhash.Hash {
|
||||||
return h.miner.AssertNumTxsInMempool(n)
|
return h.miner.AssertNumTxsInMempool(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +228,7 @@ func (h *HarnessTest) AssertOutpointInMempool(op wire.OutPoint) *wire.MsgTx {
|
||||||
|
|
||||||
// AssertTxInBlock asserts that a given txid can be found in the passed block.
|
// AssertTxInBlock asserts that a given txid can be found in the passed block.
|
||||||
func (h *HarnessTest) AssertTxInBlock(block *wire.MsgBlock,
|
func (h *HarnessTest) AssertTxInBlock(block *wire.MsgBlock,
|
||||||
txid *chainhash.Hash) {
|
txid chainhash.Hash) {
|
||||||
|
|
||||||
h.miner.AssertTxInBlock(block, txid)
|
h.miner.AssertTxInBlock(block, txid)
|
||||||
}
|
}
|
||||||
|
@ -263,13 +261,13 @@ func (h *HarnessTest) DisconnectFromMiner(tempMiner *miner.HarnessMiner) {
|
||||||
|
|
||||||
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
|
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
|
||||||
// asserts.
|
// asserts.
|
||||||
func (h *HarnessTest) GetRawMempool() []*chainhash.Hash {
|
func (h *HarnessTest) GetRawMempool() []chainhash.Hash {
|
||||||
return h.miner.GetRawMempool()
|
return h.miner.GetRawMempool()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
|
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
|
||||||
// asserts.
|
// asserts.
|
||||||
func (h *HarnessTest) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx {
|
func (h *HarnessTest) GetRawTransaction(txid chainhash.Hash) *btcutil.Tx {
|
||||||
return h.miner.GetRawTransaction(txid)
|
return h.miner.GetRawTransaction(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,11 +156,16 @@ func (h *HarnessMiner) GetBestBlock() (*chainhash.Hash, int32) {
|
||||||
|
|
||||||
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
|
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
|
||||||
// asserts.
|
// asserts.
|
||||||
func (h *HarnessMiner) GetRawMempool() []*chainhash.Hash {
|
func (h *HarnessMiner) GetRawMempool() []chainhash.Hash {
|
||||||
mempool, err := h.Client.GetRawMempool()
|
mempool, err := h.Client.GetRawMempool()
|
||||||
require.NoError(h, err, "unable to get mempool")
|
require.NoError(h, err, "unable to get mempool")
|
||||||
|
|
||||||
return mempool
|
txns := make([]chainhash.Hash, 0, len(mempool))
|
||||||
|
for _, txid := range mempool {
|
||||||
|
txns = append(txns, *txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txns
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateBlocks mine 'num' of blocks and returns them.
|
// GenerateBlocks mine 'num' of blocks and returns them.
|
||||||
|
@ -198,9 +203,9 @@ func (h *HarnessMiner) MineBlocks(num uint32) []*wire.MsgBlock {
|
||||||
// AssertNumTxsInMempool polls until finding the desired number of transactions
|
// AssertNumTxsInMempool polls until finding the desired number of transactions
|
||||||
// in the provided miner's mempool. It will assert if this number is not met
|
// in the provided miner's mempool. It will assert if this number is not met
|
||||||
// after the given timeout.
|
// after the given timeout.
|
||||||
func (h *HarnessMiner) AssertNumTxsInMempool(n int) []*chainhash.Hash {
|
func (h *HarnessMiner) AssertNumTxsInMempool(n int) []chainhash.Hash {
|
||||||
var (
|
var (
|
||||||
mem []*chainhash.Hash
|
mem []chainhash.Hash
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -222,7 +227,7 @@ func (h *HarnessMiner) AssertNumTxsInMempool(n int) []*chainhash.Hash {
|
||||||
|
|
||||||
// AssertTxInBlock asserts that a given txid can be found in the passed block.
|
// AssertTxInBlock asserts that a given txid can be found in the passed block.
|
||||||
func (h *HarnessMiner) AssertTxInBlock(block *wire.MsgBlock,
|
func (h *HarnessMiner) AssertTxInBlock(block *wire.MsgBlock,
|
||||||
txid *chainhash.Hash) {
|
txid chainhash.Hash) {
|
||||||
|
|
||||||
blockTxes := make([]chainhash.Hash, 0)
|
blockTxes := make([]chainhash.Hash, 0)
|
||||||
|
|
||||||
|
@ -264,8 +269,8 @@ func (h *HarnessMiner) MineBlocksAndAssertNumTxes(num uint32,
|
||||||
|
|
||||||
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
|
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
|
||||||
// asserts.
|
// asserts.
|
||||||
func (h *HarnessMiner) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx {
|
func (h *HarnessMiner) GetRawTransaction(txid chainhash.Hash) *btcutil.Tx {
|
||||||
tx, err := h.Client.GetRawTransaction(txid)
|
tx, err := h.Client.GetRawTransaction(&txid)
|
||||||
require.NoErrorf(h, err, "failed to get raw tx: %v", txid)
|
require.NoErrorf(h, err, "failed to get raw tx: %v", txid)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
@ -273,15 +278,15 @@ func (h *HarnessMiner) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx {
|
||||||
// GetRawTransactionVerbose makes a RPC call to the miner's
|
// GetRawTransactionVerbose makes a RPC call to the miner's
|
||||||
// GetRawTransactionVerbose and asserts.
|
// GetRawTransactionVerbose and asserts.
|
||||||
func (h *HarnessMiner) GetRawTransactionVerbose(
|
func (h *HarnessMiner) GetRawTransactionVerbose(
|
||||||
txid *chainhash.Hash) *btcjson.TxRawResult {
|
txid chainhash.Hash) *btcjson.TxRawResult {
|
||||||
|
|
||||||
tx, err := h.Client.GetRawTransactionVerbose(txid)
|
tx, err := h.Client.GetRawTransactionVerbose(&txid)
|
||||||
require.NoErrorf(h, err, "failed to get raw tx verbose: %v", txid)
|
require.NoErrorf(h, err, "failed to get raw tx verbose: %v", txid)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertTxInMempool asserts a given transaction can be found in the mempool.
|
// AssertTxInMempool asserts a given transaction can be found in the mempool.
|
||||||
func (h *HarnessMiner) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
func (h *HarnessMiner) AssertTxInMempool(txid chainhash.Hash) *wire.MsgTx {
|
||||||
err := wait.NoError(func() error {
|
err := wait.NoError(func() error {
|
||||||
// We require the RPC call to be succeeded and won't wait for
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
// it as it's an unexpected behavior.
|
// it as it's an unexpected behavior.
|
||||||
|
@ -291,8 +296,8 @@ func (h *HarnessMiner) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
||||||
return fmt.Errorf("empty mempool")
|
return fmt.Errorf("empty mempool")
|
||||||
}
|
}
|
||||||
|
|
||||||
isEqual := func(memTx *chainhash.Hash) bool {
|
isEqual := func(memTx chainhash.Hash) bool {
|
||||||
return *memTx == *txid
|
return memTx == txid
|
||||||
}
|
}
|
||||||
result := fn.Find(isEqual, mempool)
|
result := fn.Find(isEqual, mempool)
|
||||||
|
|
||||||
|
@ -309,15 +314,41 @@ func (h *HarnessMiner) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
||||||
return h.GetRawTransaction(txid).MsgTx()
|
return h.GetRawTransaction(txid).MsgTx()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertTxnsNotInMempool asserts the given txns are not found in the mempool.
|
||||||
|
// It assumes the mempool is not empty.
|
||||||
|
func (h *HarnessMiner) AssertTxnsNotInMempool(txids []chainhash.Hash) {
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
|
// it as it's an unexpected behavior.
|
||||||
|
mempool := h.GetRawMempool()
|
||||||
|
|
||||||
|
// Turn the mempool into a txn set for faster lookups.
|
||||||
|
mempoolTxns := fn.NewSet(mempool...)
|
||||||
|
|
||||||
|
// Check if any of the txids are in the mempool.
|
||||||
|
for _, txid := range txids {
|
||||||
|
// Skip if the tx is not in the mempool.
|
||||||
|
if !mempoolTxns.Contains(txid) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("expect txid %v to be NOT found in "+
|
||||||
|
"mempool", txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, wait.MinerMempoolTimeout)
|
||||||
|
|
||||||
|
require.NoError(h, err, "timeout checking txns not in mempool")
|
||||||
|
}
|
||||||
|
|
||||||
// AssertTxNotInMempool asserts a given transaction cannot be found in the
|
// AssertTxNotInMempool asserts a given transaction cannot be found in the
|
||||||
// mempool. It assumes the mempool is not empty.
|
// mempool. It assumes the mempool is not empty.
|
||||||
//
|
//
|
||||||
// NOTE: this should be used after `AssertTxInMempool` to ensure the tx has
|
// NOTE: this should be used after `AssertTxInMempool` to ensure the tx has
|
||||||
// entered the mempool before. Otherwise it might give false positive and the
|
// entered the mempool before. Otherwise it might give false positive and the
|
||||||
// tx may enter the mempool after the check.
|
// tx may enter the mempool after the check.
|
||||||
func (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx {
|
func (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) {
|
||||||
var msgTx *wire.MsgTx
|
|
||||||
|
|
||||||
err := wait.NoError(func() error {
|
err := wait.NoError(func() error {
|
||||||
// We require the RPC call to be succeeded and won't wait for
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
// it as it's an unexpected behavior.
|
// it as it's an unexpected behavior.
|
||||||
|
@ -325,7 +356,7 @@ func (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx {
|
||||||
|
|
||||||
for _, memTx := range mempool {
|
for _, memTx := range mempool {
|
||||||
// Check the values are equal.
|
// Check the values are equal.
|
||||||
if txid.IsEqual(memTx) {
|
if txid == memTx {
|
||||||
return fmt.Errorf("expect txid %v to be NOT "+
|
return fmt.Errorf("expect txid %v to be NOT "+
|
||||||
"found in mempool", txid)
|
"found in mempool", txid)
|
||||||
}
|
}
|
||||||
|
@ -335,8 +366,6 @@ func (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx {
|
||||||
}, wait.MinerMempoolTimeout)
|
}, wait.MinerMempoolTimeout)
|
||||||
|
|
||||||
require.NoError(h, err, "timeout checking tx not in mempool")
|
require.NoError(h, err, "timeout checking tx not in mempool")
|
||||||
|
|
||||||
return msgTx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendOutputsWithoutChange uses the miner to send the given outputs using the
|
// SendOutputsWithoutChange uses the miner to send the given outputs using the
|
||||||
|
@ -418,7 +447,7 @@ func (h *HarnessMiner) AssertOutpointInMempool(op wire.OutPoint) *wire.MsgTx {
|
||||||
// found. For instance, the aggregation logic used in
|
// found. For instance, the aggregation logic used in
|
||||||
// sweeping HTLC outputs will update the mempool by
|
// sweeping HTLC outputs will update the mempool by
|
||||||
// replacing the HTLC spending txes with a single one.
|
// replacing the HTLC spending txes with a single one.
|
||||||
tx, err := h.Client.GetRawTransaction(txid)
|
tx, err := h.Client.GetRawTransaction(&txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue