mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-21 22:11:41 +01:00
itest: add taproot support for all variants of runMultiHopHtlcClaimTest
This commit is contained in:
parent
5739061f13
commit
7c5be4d056
3 changed files with 290 additions and 43 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/chainreg"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||
|
@ -49,6 +50,67 @@ var commitWithZeroConf = []struct {
|
|||
commitType: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE,
|
||||
zeroConf: true,
|
||||
},
|
||||
{
|
||||
commitType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||
zeroConf: false,
|
||||
},
|
||||
{
|
||||
commitType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||
zeroConf: true,
|
||||
},
|
||||
}
|
||||
|
||||
// makeRouteHints creates a route hints that will allow Carol to be reached
|
||||
// using an unadvertised channel created by Bob (Bob -> Carol). If the zeroConf
|
||||
// bool is set, then the scid alias of Bob will be used in place.
|
||||
func makeRouteHints(bob, carol *node.HarnessNode,
|
||||
zeroConf bool) []*lnrpc.RouteHint {
|
||||
|
||||
carolChans := carol.RPC.ListChannels(
|
||||
&lnrpc.ListChannelsRequest{},
|
||||
)
|
||||
|
||||
carolChan := carolChans.Channels[0]
|
||||
|
||||
hopHint := &lnrpc.HopHint{
|
||||
NodeId: carolChan.RemotePubkey,
|
||||
ChanId: carolChan.ChanId,
|
||||
FeeBaseMsat: uint32(
|
||||
chainreg.DefaultBitcoinBaseFeeMSat,
|
||||
),
|
||||
FeeProportionalMillionths: uint32(
|
||||
chainreg.DefaultBitcoinFeeRate,
|
||||
),
|
||||
CltvExpiryDelta: chainreg.DefaultBitcoinTimeLockDelta,
|
||||
}
|
||||
|
||||
if zeroConf {
|
||||
bobChans := bob.RPC.ListChannels(
|
||||
&lnrpc.ListChannelsRequest{},
|
||||
)
|
||||
|
||||
// Now that we have Bob's channels, scan for the channel he has
|
||||
// open to Carol so we can use the proper scid.
|
||||
var found bool
|
||||
for _, bobChan := range bobChans.Channels {
|
||||
if bobChan.RemotePubkey == carol.PubKeyStr {
|
||||
hopHint.ChanId = bobChan.AliasScids[0]
|
||||
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
bob.Fatalf("unable to create route hint")
|
||||
}
|
||||
}
|
||||
|
||||
return []*lnrpc.RouteHint{
|
||||
{
|
||||
HopHints: []*lnrpc.HopHint{hopHint},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// caseRunner defines a single test case runner.
|
||||
|
@ -131,6 +193,13 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
|
|||
dustPayHash := ht.Random32Bytes()
|
||||
payHash := ht.Random32Bytes()
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
alice.RPC.SendPayment(&routerrpc.SendPaymentRequest{
|
||||
Dest: carolPubKey,
|
||||
Amt: int64(dustHtlcAmt),
|
||||
|
@ -138,6 +207,7 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
|
|||
FinalCltvDelta: finalCltvDelta,
|
||||
TimeoutSeconds: 60,
|
||||
FeeLimitMsat: noFeeLimitMsat,
|
||||
RouteHints: routeHints,
|
||||
})
|
||||
|
||||
alice.RPC.SendPayment(&routerrpc.SendPaymentRequest{
|
||||
|
@ -147,6 +217,7 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
|
|||
FinalCltvDelta: finalCltvDelta,
|
||||
TimeoutSeconds: 60,
|
||||
FeeLimitMsat: noFeeLimitMsat,
|
||||
RouteHints: routeHints,
|
||||
})
|
||||
|
||||
// Verify that all nodes in the path now have two HTLC's with the
|
||||
|
@ -155,6 +226,18 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
|
|||
ht.AssertActiveHtlcs(bob, dustPayHash, payHash)
|
||||
ht.AssertActiveHtlcs(carol, dustPayHash, payHash)
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Increase the fee estimate so that the following force close tx will
|
||||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
@ -166,7 +249,7 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
|
|||
numBlocks := padCLTV(
|
||||
uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta),
|
||||
)
|
||||
ht.MineBlocks(numBlocks)
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// Bob's force close transaction should now be found in the mempool. If
|
||||
// there are anchors, we also expect Bob's anchor sweep.
|
||||
|
@ -286,6 +369,13 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
|
|||
ht, alice, bob, false, c, zeroConf,
|
||||
)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
// With the network active, we'll now add a new hodl invoice at Carol's
|
||||
// end. Make sure the cltv expiry delta is large enough, otherwise Bob
|
||||
// won't send out the outgoing htlc.
|
||||
|
@ -297,6 +387,7 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
|
|||
Value: invoiceAmt,
|
||||
CltvExpiry: finalCltvDelta,
|
||||
Hash: payHash[:],
|
||||
RouteHints: routeHints,
|
||||
}
|
||||
carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -319,6 +410,18 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
|
|||
ht.AssertActiveHtlcs(bob, payHash[:])
|
||||
ht.AssertActiveHtlcs(carol, payHash[:])
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Wait for carol to mark invoice as accepted. There is a small gap to
|
||||
// bridge between adding the htlc to the channel and executing the exit
|
||||
// hop logic.
|
||||
|
@ -337,12 +440,16 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
|
|||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
||||
// Now we'll mine enough blocks to prompt carol to actually go to the
|
||||
// chain in order to sweep her HTLC since the value is high enough.
|
||||
// We now advance the block height to the point where Carol will force
|
||||
// close her channel with Bob, broadcast the closing tx but keep it
|
||||
// unconfirmed.
|
||||
numBlocks := padCLTV(uint32(
|
||||
invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta,
|
||||
))
|
||||
ht.MineBlocks(numBlocks)
|
||||
|
||||
// Now we'll mine enough blocks to prompt carol to actually go to the
|
||||
// chain in order to sweep her HTLC since the value is high enough.
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// At this point, Carol should broadcast her active commitment
|
||||
// transaction in order to go to the chain and sweep her HTLC. If there
|
||||
|
@ -379,7 +486,7 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
|
|||
// Carol should broadcast her second level HTLC transaction and Bob
|
||||
// should broadcast a sweep tx to sweep his output in the channel with
|
||||
// Carol, and another sweep tx to sweep his anchor output.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
expectedTxes = 3
|
||||
|
||||
// Carol should broadcast her second level HTLC transaction and Bob
|
||||
|
@ -491,6 +598,13 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
// opens up the base for out tests.
|
||||
const htlcAmt = btcutil.Amount(300_000)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
// We'll now send a single HTLC across our multi-hop network.
|
||||
carolPubKey := carol.PubKey[:]
|
||||
payHash := ht.Random32Bytes()
|
||||
|
@ -501,6 +615,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
FinalCltvDelta: finalCltvDelta,
|
||||
TimeoutSeconds: 60,
|
||||
FeeLimitMsat: noFeeLimitMsat,
|
||||
RouteHints: routeHints,
|
||||
}
|
||||
alice.RPC.SendPayment(req)
|
||||
|
||||
|
@ -510,6 +625,18 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
ht.AssertActiveHtlcs(bob, payHash)
|
||||
ht.AssertActiveHtlcs(carol, payHash)
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Increase the fee estimate so that the following force close tx will
|
||||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
@ -523,9 +650,9 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
bob, bobChanPoint, hasAnchors, stream,
|
||||
)
|
||||
|
||||
// Record how many blocks have mined. At this step
|
||||
// Increase the blocks mined. At this step
|
||||
// AssertStreamChannelForceClosed mines one block.
|
||||
blocksMined := uint32(1)
|
||||
blocksMined++
|
||||
|
||||
// If the channel closed has anchors, we should expect to see a sweep
|
||||
// transaction for Carol's anchor.
|
||||
|
@ -546,7 +673,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
// CSV expires and the commitment was already mined inside
|
||||
// AssertStreamChannelForceClosed(), so mine one block less
|
||||
// than defaultCSV in order to perform mempool assertions.
|
||||
ht.MineBlocks(defaultCSV - blocksMined)
|
||||
ht.MineBlocks(defaultCSV - 1)
|
||||
|
||||
commitSweepTx := ht.Miner.AssertOutpointInMempool(
|
||||
bobCommitOutpoint,
|
||||
|
@ -555,12 +682,13 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||
ht.Miner.AssertTxInBlock(block, &txid)
|
||||
|
||||
blocksMined = defaultCSV + 1
|
||||
blocksMined += defaultCSV
|
||||
}
|
||||
|
||||
// We'll now mine enough blocks for the HTLC to expire. After this, Bob
|
||||
// should hand off the now expired HTLC output to the utxo nursery.
|
||||
numBlocks := padCLTV(finalCltvDelta)
|
||||
numBlocks := padCLTV(uint32(finalCltvDelta) -
|
||||
lncfg.DefaultOutgoingBroadcastDelta)
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// Bob's pending channel report should show that he has a single HTLC
|
||||
|
@ -647,6 +775,13 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
// opens up the base for out tests.
|
||||
const htlcAmt = btcutil.Amount(30000)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
// We'll now send a single HTLC across our multi-hop network.
|
||||
var preimage lntypes.Preimage
|
||||
copy(preimage[:], ht.Random32Bytes())
|
||||
|
@ -655,6 +790,7 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
Value: int64(htlcAmt),
|
||||
CltvExpiry: finalCltvDelta,
|
||||
Hash: payHash[:],
|
||||
RouteHints: routeHints,
|
||||
}
|
||||
carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -668,6 +804,18 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
}
|
||||
alice.RPC.SendPayment(req)
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Once the HTLC has cleared, all the nodes in our mini network should
|
||||
// show that the HTLC has been locked in.
|
||||
ht.AssertActiveHtlcs(alice, payHash[:])
|
||||
|
@ -690,6 +838,10 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
carol, bobChanPoint, hasAnchors, closeStream,
|
||||
)
|
||||
|
||||
// Increase the blocks mined. At this step
|
||||
// AssertStreamChannelForceClosed mines one block.
|
||||
blocksMined++
|
||||
|
||||
// At this point, Bob should have a pending force close channel as
|
||||
// Carol has gone directly to chain.
|
||||
ht.AssertNumPendingForceClose(bob, 1)
|
||||
|
@ -701,7 +853,7 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
expectedTxes = 1
|
||||
|
||||
// Bob can sweep his commit and anchor outputs immediately.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
expectedTxes = 2
|
||||
|
||||
// Bob can't sweep his commit output yet as he was the initiator of a
|
||||
|
@ -719,12 +871,13 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
|
|||
// Next, we'll mine enough blocks for the HTLC to expire. At this
|
||||
// point, Bob should hand off the output to his internal utxo nursery,
|
||||
// which will broadcast a sweep transaction.
|
||||
numBlocks := padCLTV(finalCltvDelta - 1)
|
||||
ht.MineBlocks(numBlocks)
|
||||
numBlocks := padCLTV(uint32(finalCltvDelta) -
|
||||
lncfg.DefaultOutgoingBroadcastDelta)
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// If we check Bob's pending channel report, it should show that he has
|
||||
// a single HTLC that's now in the second stage, as skip the initial
|
||||
// first stage since this is a direct HTLC.
|
||||
// a single HTLC that's now in the second stage, as it skipped the
|
||||
// initial first stage since this is a direct HTLC.
|
||||
ht.AssertNumHTLCsAndStage(bob, bobChanPoint, 1, 2)
|
||||
|
||||
// We need to generate an additional block to trigger the sweep.
|
||||
|
@ -796,6 +949,13 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
ht, alice, bob, false, c, zeroConf,
|
||||
)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
// With the network active, we'll now add a new hodl invoice at Carol's
|
||||
// end. Make sure the cltv expiry delta is large enough, otherwise Bob
|
||||
// won't send out the outgoing htlc.
|
||||
|
@ -807,6 +967,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
Value: invoiceAmt,
|
||||
CltvExpiry: finalCltvDelta,
|
||||
Hash: payHash[:],
|
||||
RouteHints: routeHints,
|
||||
}
|
||||
carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -834,6 +995,18 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
// hop logic.
|
||||
ht.AssertInvoiceState(stream, lnrpc.Invoice_ACCEPTED)
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Increase the fee estimate so that the following force close tx will
|
||||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
@ -848,6 +1021,10 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
bob, aliceChanPoint, hasAnchors, closeStream,
|
||||
)
|
||||
|
||||
// Increase the blocks mined. At this step
|
||||
// AssertStreamChannelForceClosed mines one block.
|
||||
blocksMined++
|
||||
|
||||
var expectedTxes int
|
||||
switch c {
|
||||
// Alice will sweep her commitment output immediately.
|
||||
|
@ -855,7 +1032,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
expectedTxes = 1
|
||||
|
||||
// Alice will sweep her commitment and anchor output immediately.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
expectedTxes = 2
|
||||
|
||||
// Alice will sweep her anchor output immediately. Her commitment
|
||||
|
@ -880,11 +1057,12 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
// channel arbitrator won't go to chain.
|
||||
carol.RPC.SettleInvoice(preimage[:])
|
||||
|
||||
// We'll now mine enough blocks so Carol decides that she needs to go
|
||||
// on-chain to claim the HTLC as Bob has been inactive.
|
||||
numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry-
|
||||
lncfg.DefaultIncomingBroadcastDelta) - 1)
|
||||
ht.MineBlocks(numBlocks)
|
||||
// We now advance the block height to the point where Carol will force
|
||||
// close her channel with Bob, broadcast the closing tx but keep it
|
||||
// unconfirmed.
|
||||
numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry -
|
||||
lncfg.DefaultIncomingBroadcastDelta))
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// Carol's commitment transaction should now be in the mempool. If
|
||||
// there is an anchor, Carol will sweep that too.
|
||||
|
@ -918,7 +1096,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
|
|||
|
||||
// Carol will broadcast her second level HTLC transaction and Bob will
|
||||
// sweep his commitment and anchor output.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
expectedTxes = 3
|
||||
|
||||
// Carol will broadcast her second level HTLC transaction, and Bob will
|
||||
|
@ -1090,6 +1268,13 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
ht, alice, bob, false, c, zeroConf,
|
||||
)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice can actually find a route.
|
||||
var routeHints []*lnrpc.RouteHint
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
routeHints = makeRouteHints(bob, carol, zeroConf)
|
||||
}
|
||||
|
||||
// With the network active, we'll now add a new hodl invoice at Carol's
|
||||
// end. Make sure the cltv expiry delta is large enough, otherwise Bob
|
||||
// won't send out the outgoing htlc.
|
||||
|
@ -1101,6 +1286,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
Value: invoiceAmt,
|
||||
CltvExpiry: finalCltvDelta,
|
||||
Hash: payHash[:],
|
||||
RouteHints: routeHints,
|
||||
}
|
||||
carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -1128,6 +1314,18 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
// hop logic.
|
||||
ht.AssertInvoiceState(stream, lnrpc.Invoice_ACCEPTED)
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && routeHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Increase the fee estimate so that the following force close tx will
|
||||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
@ -1143,9 +1341,9 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
alice, aliceChanPoint, hasAnchors, closeStream,
|
||||
)
|
||||
|
||||
// Record how many blocks have mined. At this step
|
||||
// Increase the blocks mined. At this step
|
||||
// AssertStreamChannelForceClosed mines one block.
|
||||
blocksMined := uint32(1)
|
||||
blocksMined++
|
||||
|
||||
// Wait for the channel to be marked pending force close.
|
||||
ht.AssertChannelPendingForceClose(alice, aliceChanPoint)
|
||||
|
@ -1164,8 +1362,8 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
// commit sweep tx will be broadcast immediately before it can
|
||||
// be included in a block, so mine one less than defaultCSV in
|
||||
// order to perform mempool assertions.
|
||||
ht.MineBlocks(defaultCSV - blocksMined)
|
||||
blocksMined = defaultCSV
|
||||
ht.MineBlocks(defaultCSV - 1)
|
||||
blocksMined += (defaultCSV - 1)
|
||||
|
||||
// Alice should now sweep her funds.
|
||||
ht.Miner.AssertNumTxsInMempool(1)
|
||||
|
@ -1224,7 +1422,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
|
|||
// Carol should broadcast her second level HTLC transaction and Bob
|
||||
// should broadcast a transaction to sweep his commitment output and
|
||||
// another to sweep his anchor output.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
expectedTxes = 3
|
||||
|
||||
// Carol should broadcast her second level HTLC transaction and Bob
|
||||
|
@ -1353,21 +1551,35 @@ func testMultiHopHtlcAggregation(ht *lntest.HarnessTest) {
|
|||
func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
||||
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
|
||||
|
||||
// First, we'll create a three hop network: Alice -> Bob -> Carol.
|
||||
aliceChanPoint, bobChanPoint, carol := createThreeHopNetwork(
|
||||
ht, alice, bob, false, c, zeroConf,
|
||||
)
|
||||
|
||||
// For neutrino backend, we need one additional UTXO to create
|
||||
// the sweeping tx for the second-level success txes.
|
||||
if ht.IsNeutrinoBackend() {
|
||||
ht.FundCoins(btcutil.SatoshiPerBitcoin, bob)
|
||||
}
|
||||
|
||||
// First, we'll create a three hop network: Alice -> Bob -> Carol.
|
||||
aliceChanPoint, bobChanPoint, carol := createThreeHopNetwork(
|
||||
ht, alice, bob, false, c, zeroConf,
|
||||
)
|
||||
|
||||
// If this is a taproot channel, then we'll need to make some manual
|
||||
// route hints so Alice+Carol can actually find a route.
|
||||
var (
|
||||
carolRouteHints []*lnrpc.RouteHint
|
||||
aliceRouteHints []*lnrpc.RouteHint
|
||||
)
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
carolRouteHints = makeRouteHints(bob, carol, zeroConf)
|
||||
aliceRouteHints = makeRouteHints(bob, alice, zeroConf)
|
||||
}
|
||||
|
||||
// To ensure we have capacity in both directions of the route, we'll
|
||||
// make a fairly large payment Alice->Carol and settle it.
|
||||
const reBalanceAmt = 500_000
|
||||
invoice := &lnrpc.Invoice{Value: reBalanceAmt}
|
||||
invoice := &lnrpc.Invoice{
|
||||
Value: reBalanceAmt,
|
||||
RouteHints: carolRouteHints,
|
||||
}
|
||||
resp := carol.RPC.AddInvoice(invoice)
|
||||
ht.CompletePaymentRequests(alice, []string{resp.PaymentRequest})
|
||||
|
||||
|
@ -1398,6 +1610,7 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
Value: invoiceAmt,
|
||||
CltvExpiry: finalCltvDelta,
|
||||
Hash: payHash[:],
|
||||
RouteHints: carolRouteHints,
|
||||
}
|
||||
carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -1419,6 +1632,7 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
Value: invoiceAmt,
|
||||
CltvExpiry: thawHeightDelta - 4,
|
||||
Hash: payHash[:],
|
||||
RouteHints: aliceRouteHints,
|
||||
}
|
||||
aliceInvoice := alice.RPC.AddHoldInvoice(invoiceReq)
|
||||
|
||||
|
@ -1472,6 +1686,18 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
ht.AssertInvoiceState(stream, lnrpc.Invoice_ACCEPTED)
|
||||
}
|
||||
|
||||
// blocksMined records how many blocks have mined after the creation of
|
||||
// the invoice so it can be used to calculate how many more blocks need
|
||||
// to be mined to trigger a force close later on.
|
||||
var blocksMined uint32
|
||||
|
||||
// If this is a private channel, and it was zero conf, then we'll need
|
||||
// to mine one block to confirm the channels created above.
|
||||
if zeroConf && carolRouteHints != nil {
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
blocksMined++
|
||||
}
|
||||
|
||||
// Increase the fee estimate so that the following force close tx will
|
||||
// be cpfp'ed.
|
||||
ht.SetFeeEstimate(30000)
|
||||
|
@ -1488,7 +1714,7 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
numBlocks := padCLTV(
|
||||
uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta),
|
||||
)
|
||||
ht.MineBlocks(numBlocks)
|
||||
ht.MineBlocks(numBlocks - blocksMined)
|
||||
|
||||
// Bob's force close transaction should now be found in the mempool. If
|
||||
// there are anchors, we also expect Bob's anchor sweep.
|
||||
|
@ -1563,7 +1789,9 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
// Carol will also sweep her commitment and anchor output as separate
|
||||
// txs (since it will be low fee).
|
||||
case lnrpc.CommitmentType_ANCHORS,
|
||||
lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
|
||||
lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE,
|
||||
lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
|
||||
expectedTxes = 4
|
||||
|
||||
default:
|
||||
|
@ -1666,7 +1894,7 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
|
|||
// Mining one additional block, Bob's second level tx is mature, and he
|
||||
// can sweep the output. Before the blocks are mined, we should expect
|
||||
// to see Bob's commit sweep in the mempool.
|
||||
case lnrpc.CommitmentType_ANCHORS:
|
||||
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||
|
||||
// Since Bob is the initiator of the Bob-Carol script-enforced leased
|
||||
|
@ -1782,8 +2010,13 @@ func createThreeHopNetwork(ht *lntest.HarnessTest,
|
|||
)
|
||||
}
|
||||
|
||||
// Prepare params for Alice.
|
||||
var privateChan bool
|
||||
if c == lnrpc.CommitmentType_SIMPLE_TAPROOT {
|
||||
privateChan = true
|
||||
}
|
||||
|
||||
aliceParams := lntest.OpenChannelParams{
|
||||
Private: privateChan,
|
||||
Amt: chanAmt,
|
||||
CommitmentType: c,
|
||||
FundingShim: aliceFundingShim,
|
||||
|
@ -1802,6 +2035,7 @@ func createThreeHopNetwork(ht *lntest.HarnessTest,
|
|||
// Prepare params for Bob.
|
||||
bobParams := lntest.OpenChannelParams{
|
||||
Amt: chanAmt,
|
||||
Private: privateChan,
|
||||
CommitmentType: c,
|
||||
FundingShim: bobFundingShim,
|
||||
ZeroConf: zeroConf,
|
||||
|
@ -1840,8 +2074,18 @@ func createThreeHopNetwork(ht *lntest.HarnessTest,
|
|||
}
|
||||
|
||||
// Make sure alice and carol know each other's channels.
|
||||
ht.AssertTopologyChannelOpen(alice, bobChanPoint)
|
||||
ht.AssertTopologyChannelOpen(carol, aliceChanPoint)
|
||||
//
|
||||
// We'll only do this though if it wasn't a private channel we opened
|
||||
// earlier.
|
||||
if !privateChan {
|
||||
ht.AssertTopologyChannelOpen(alice, bobChanPoint)
|
||||
ht.AssertTopologyChannelOpen(carol, aliceChanPoint)
|
||||
} else {
|
||||
// Otherwise, we want to wait for all the channels to be shown
|
||||
// as active before we proceed.
|
||||
ht.AssertChannelExists(alice, aliceChanPoint)
|
||||
ht.AssertChannelExists(carol, bobChanPoint)
|
||||
}
|
||||
|
||||
return aliceChanPoint, bobChanPoint, carol
|
||||
}
|
||||
|
|
|
@ -1782,10 +1782,12 @@ func (h *HarnessTest) OpenMultiChannelsAsync(
|
|||
// Wait for the channel open event from the stream.
|
||||
cp := h.WaitForChannelOpenEvent(req.stream)
|
||||
|
||||
// Check that both alice and bob have seen the channel
|
||||
// from their channel watch request.
|
||||
h.AssertTopologyChannelOpen(req.Local, cp)
|
||||
h.AssertTopologyChannelOpen(req.Remote, cp)
|
||||
if !req.Param.Private {
|
||||
// Check that both alice and bob have seen the channel
|
||||
// from their channel watch request.
|
||||
h.AssertTopologyChannelOpen(req.Local, cp)
|
||||
h.AssertTopologyChannelOpen(req.Remote, cp)
|
||||
}
|
||||
|
||||
// Finally, check that the channel can be seen in their
|
||||
// ListChannels.
|
||||
|
|
|
@ -137,6 +137,7 @@ func CommitTypeHasTaproot(commitType lnrpc.CommitmentType) bool {
|
|||
func CommitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
|
||||
switch commitType {
|
||||
case lnrpc.CommitmentType_ANCHORS,
|
||||
lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||
lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
|
||||
return true
|
||||
default:
|
||||
|
|
Loading…
Add table
Reference in a new issue