mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
itest: add new test to check BumpFee
and PendingSweeps
This commit is contained in:
parent
11a276e222
commit
6f55a7af05
@ -459,8 +459,8 @@ var allTestCases = []*lntest.TestCase{
|
||||
TestFunc: testSignVerifyMessage,
|
||||
},
|
||||
{
|
||||
Name: "cpfp",
|
||||
TestFunc: testCPFP,
|
||||
Name: "bumpfee",
|
||||
TestFunc: testBumpFee,
|
||||
},
|
||||
{
|
||||
Name: "taproot",
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lntest/node"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/sweep"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -210,120 +209,6 @@ func testChainKitSendOutputsAnchorReserve(ht *lntest.HarnessTest) {
|
||||
ht.CloseChannel(charlie, outpoint)
|
||||
}
|
||||
|
||||
// testCPFP ensures that the daemon can bump an unconfirmed transaction's fee
|
||||
// rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction.
|
||||
//
|
||||
// TODO(wilmer): Add RBF case once btcd supports it.
|
||||
func testCPFP(ht *lntest.HarnessTest) {
|
||||
runCPFP(ht, ht.Alice, ht.Bob)
|
||||
}
|
||||
|
||||
// runCPFP ensures that the daemon can bump an unconfirmed transaction's fee
|
||||
// rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction.
|
||||
func runCPFP(ht *lntest.HarnessTest, alice, bob *node.HarnessNode) {
|
||||
// TODO(yy): fix the test when `BumpFee` is updated.
|
||||
ht.Skipf("skipped")
|
||||
|
||||
// Skip this test for neutrino, as it's not aware of mempool
|
||||
// transactions.
|
||||
if ht.IsNeutrinoBackend() {
|
||||
ht.Skipf("skipping CPFP test for neutrino backend")
|
||||
}
|
||||
|
||||
// We'll start the test by sending Alice some coins, which she'll use
|
||||
// to send to Bob.
|
||||
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
|
||||
|
||||
// Create an address for Bob to send the coins to.
|
||||
req := &lnrpc.NewAddressRequest{
|
||||
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
|
||||
}
|
||||
resp := bob.RPC.NewAddress(req)
|
||||
|
||||
// Send the coins from Alice to Bob. We should expect a transaction to
|
||||
// be broadcast and seen in the mempool.
|
||||
sendReq := &lnrpc.SendCoinsRequest{
|
||||
Addr: resp.Address,
|
||||
Amount: btcutil.SatoshiPerBitcoin,
|
||||
TargetConf: 6,
|
||||
}
|
||||
alice.RPC.SendCoins(sendReq)
|
||||
txid := ht.Miner.AssertNumTxsInMempool(1)[0]
|
||||
|
||||
// We'll then extract the raw transaction from the mempool in order to
|
||||
// determine the index of Bob's output.
|
||||
tx := ht.Miner.GetRawTransaction(txid)
|
||||
bobOutputIdx := -1
|
||||
for i, txOut := range tx.MsgTx().TxOut {
|
||||
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
|
||||
txOut.PkScript, ht.Miner.ActiveNet,
|
||||
)
|
||||
require.NoErrorf(ht, err, "unable to extract address "+
|
||||
"from pkScript=%x: %v", txOut.PkScript, err)
|
||||
|
||||
if addrs[0].String() == resp.Address {
|
||||
bobOutputIdx = i
|
||||
}
|
||||
}
|
||||
require.NotEqual(ht, -1, bobOutputIdx, "bob's output was not found "+
|
||||
"within the transaction")
|
||||
|
||||
// Wait until bob has seen the tx and considers it as owned.
|
||||
op := &lnrpc.OutPoint{
|
||||
TxidBytes: txid[:],
|
||||
OutputIndex: uint32(bobOutputIdx),
|
||||
}
|
||||
ht.AssertUTXOInWallet(bob, op, "")
|
||||
|
||||
// We'll attempt to bump the fee of this transaction by performing a
|
||||
// CPFP from Alice's point of view.
|
||||
maxFeeRate := uint64(sweep.DefaultMaxFeeRate)
|
||||
bumpFeeReq := &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a higher fee rate than the default max and expect the
|
||||
// sweeper to cap the fee rate at the max value.
|
||||
SatPerVbyte: maxFeeRate * 2,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
}
|
||||
bob.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// We should now expect to see two transactions within the mempool, a
|
||||
// parent and its child.
|
||||
ht.Miner.AssertNumTxsInMempool(2)
|
||||
|
||||
// We should also expect to see the output being swept by the
|
||||
// UtxoSweeper. We'll ensure it's using the fee rate specified.
|
||||
pendingSweepsResp := bob.RPC.PendingSweeps()
|
||||
require.Len(ht, pendingSweepsResp.PendingSweeps, 1,
|
||||
"expected to find 1 pending sweep")
|
||||
pendingSweep := pendingSweepsResp.PendingSweeps[0]
|
||||
require.Equal(ht, pendingSweep.Outpoint.TxidBytes, op.TxidBytes,
|
||||
"output txid not matched")
|
||||
require.Equal(ht, pendingSweep.Outpoint.OutputIndex, op.OutputIndex,
|
||||
"output index not matched")
|
||||
|
||||
// Also validate that the fee rate is capped at the max value.
|
||||
require.Equalf(ht, maxFeeRate, pendingSweep.SatPerVbyte,
|
||||
"sweep sat per vbyte not matched, want %v, got %v",
|
||||
maxFeeRate, pendingSweep.SatPerVbyte)
|
||||
|
||||
// Mine a block to clean up the unconfirmed transactions.
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
|
||||
// The input used to CPFP should no longer be pending.
|
||||
err := wait.NoError(func() error {
|
||||
resp := bob.RPC.PendingSweeps()
|
||||
if len(resp.PendingSweeps) != 0 {
|
||||
return fmt.Errorf("expected 0 pending sweeps, found %d",
|
||||
len(resp.PendingSweeps))
|
||||
}
|
||||
|
||||
return nil
|
||||
}, defaultTimeout)
|
||||
require.NoError(ht, err, "timeout checking bob's pending sweeps")
|
||||
}
|
||||
|
||||
// testAnchorReservedValue tests that we won't allow sending transactions when
|
||||
// that would take the value we reserve for anchor fee bumping out of our
|
||||
// wallet.
|
||||
|
@ -114,10 +114,10 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
|
||||
runDeriveSharedKey(tt, wo)
|
||||
},
|
||||
}, {
|
||||
name: "cpfp",
|
||||
name: "bumpfee",
|
||||
sendCoins: true,
|
||||
fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
|
||||
runCPFP(tt, wo, carol)
|
||||
runBumpFee(tt, wo)
|
||||
},
|
||||
}, {
|
||||
name: "psbt",
|
||||
|
@ -11,11 +11,14 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/node"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/routing"
|
||||
"github.com/lightningnetwork/lnd/sweep"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -857,3 +860,317 @@ func createSimpleNetwork(ht *lntest.HarnessTest, nodeCfg []string,
|
||||
|
||||
return resp, nodes
|
||||
}
|
||||
|
||||
// testBumpFee checks that when a new input is requested, it's first bumped via
|
||||
// CPFP, then RBF. Along the way, we check the `BumpFee` can properly update
|
||||
// the fee function used by supplying new params.
|
||||
func testBumpFee(ht *lntest.HarnessTest) {
|
||||
runBumpFee(ht, ht.Alice)
|
||||
}
|
||||
|
||||
// runBumpFee checks the `BumpFee` RPC can properly bump the fee of a given
|
||||
// input.
|
||||
func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
|
||||
// Skip this test for neutrino, as it's not aware of mempool
|
||||
// transactions.
|
||||
if ht.IsNeutrinoBackend() {
|
||||
ht.Skipf("skipping BumpFee test for neutrino backend")
|
||||
}
|
||||
|
||||
// startFeeRate is the min fee rate in sats/vbyte. This value should be
|
||||
// used as the starting fee rate when the default no deadline is used.
|
||||
startFeeRate := uint64(1)
|
||||
|
||||
// We'll start the test by sending Alice some coins, which she'll use
|
||||
// to send to Bob.
|
||||
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
|
||||
|
||||
// Alice sends a coin to herself.
|
||||
tx := ht.SendCoins(alice, alice, btcutil.SatoshiPerBitcoin)
|
||||
txid := tx.TxHash()
|
||||
|
||||
// Alice now tries to bump the first output on this tx.
|
||||
op := &lnrpc.OutPoint{
|
||||
TxidBytes: txid[:],
|
||||
OutputIndex: uint32(0),
|
||||
}
|
||||
value := btcutil.Amount(tx.TxOut[0].Value)
|
||||
|
||||
// assertPendingSweepResp is a helper closure that asserts the response
|
||||
// from `PendingSweep` RPC is returned with expected values. It also
|
||||
// returns the sweeping tx for further checks.
|
||||
assertPendingSweepResp := func(broadcastAttempts uint32, budget uint64,
|
||||
deadline uint32, startingFeeRate uint64) *wire.MsgTx {
|
||||
|
||||
// Alice should still have one pending sweep.
|
||||
pendingSweep := ht.AssertNumPendingSweeps(alice, 1)[0]
|
||||
|
||||
// Validate all fields returned from `PendingSweeps` are as
|
||||
// expected.
|
||||
require.Equal(ht, op.TxidBytes, pendingSweep.Outpoint.TxidBytes)
|
||||
require.Equal(ht, op.OutputIndex,
|
||||
pendingSweep.Outpoint.OutputIndex)
|
||||
require.Equal(ht, walletrpc.WitnessType_TAPROOT_PUB_KEY_SPEND,
|
||||
pendingSweep.WitnessType)
|
||||
require.EqualValuesf(ht, value, pendingSweep.AmountSat,
|
||||
"amount not matched: want=%d, got=%d", value,
|
||||
pendingSweep.AmountSat)
|
||||
require.True(ht, pendingSweep.Immediate)
|
||||
|
||||
require.Equal(ht, broadcastAttempts,
|
||||
pendingSweep.BroadcastAttempts)
|
||||
require.EqualValuesf(ht, budget, pendingSweep.Budget,
|
||||
"budget not matched: want=%d, got=%d", budget,
|
||||
pendingSweep.Budget)
|
||||
|
||||
// Since the request doesn't specify a deadline, we expect the
|
||||
// existing deadline to be used.
|
||||
require.Equalf(ht, deadline, pendingSweep.DeadlineHeight,
|
||||
"deadline height not matched: want=%d, got=%d",
|
||||
deadline, pendingSweep.DeadlineHeight)
|
||||
|
||||
// Since the request specifies a starting fee rate, we expect
|
||||
// that to be used as the starting fee rate.
|
||||
require.Equalf(ht, startingFeeRate,
|
||||
pendingSweep.RequestedSatPerVbyte, "requested "+
|
||||
"starting fee rate not matched: want=%d, "+
|
||||
"got=%d", startingFeeRate,
|
||||
pendingSweep.RequestedSatPerVbyte)
|
||||
|
||||
// We expect to see Alice's original tx and her CPFP tx in the
|
||||
// mempool.
|
||||
txns := ht.Miner.GetNumTxsFromMempool(2)
|
||||
|
||||
// Find the sweeping tx - assume it's the first item, if it has
|
||||
// the same txid as the parent tx, use the second item.
|
||||
sweepTx := txns[0]
|
||||
if sweepTx.TxHash() == tx.TxHash() {
|
||||
sweepTx = txns[1]
|
||||
}
|
||||
|
||||
return sweepTx
|
||||
}
|
||||
|
||||
// assertFeeRateEqual is a helper closure that asserts the fee rate of
|
||||
// the pending sweep tx is equal to the expected fee rate.
|
||||
assertFeeRateEqual := func(expected uint64) {
|
||||
err := wait.NoError(func() error {
|
||||
// Alice should still have one pending sweep.
|
||||
pendingSweep := ht.AssertNumPendingSweeps(alice, 1)[0]
|
||||
|
||||
if pendingSweep.SatPerVbyte == expected {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("expected current fee rate %d, got "+
|
||||
"%d", expected, pendingSweep.SatPerVbyte)
|
||||
}, wait.DefaultTimeout)
|
||||
require.NoError(ht, err, "fee rate not updated")
|
||||
}
|
||||
|
||||
// assertFeeRateGreater is a helper closure that asserts the fee rate
|
||||
// of the pending sweep tx is greater than the expected fee rate.
|
||||
assertFeeRateGreater := func(expected uint64) {
|
||||
err := wait.NoError(func() error {
|
||||
// Alice should still have one pending sweep.
|
||||
pendingSweep := ht.AssertNumPendingSweeps(alice, 1)[0]
|
||||
|
||||
if pendingSweep.SatPerVbyte > expected {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("expected current fee rate greater "+
|
||||
"than %d, got %d", expected,
|
||||
pendingSweep.SatPerVbyte)
|
||||
}, wait.DefaultTimeout)
|
||||
require.NoError(ht, err, "fee rate not updated")
|
||||
}
|
||||
|
||||
// First bump request - we'll specify nothing except `Immediate` to let
|
||||
// the sweeper handle the fee, and we expect a fee func that has,
|
||||
// - starting fee rate: 1 sat/vbyte (min relay fee rate).
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 50% of the input value.
|
||||
bumpFeeReq := &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Since the request doesn't specify a deadline, we expect the default
|
||||
// deadline to be used.
|
||||
_, currentHeight := ht.Miner.GetBestBlock()
|
||||
deadline := uint32(currentHeight + sweep.DefaultDeadlineDelta)
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 1.
|
||||
// - starting fee rate: 1 sat/vbyte (min relay fee rate).
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 50% of the input value.
|
||||
sweepTx1 := assertPendingSweepResp(1, uint64(value/2), deadline, 0)
|
||||
|
||||
// Since the request doesn't specify a starting fee rate, we expect the
|
||||
// min relay fee rate is used as the current fee rate.
|
||||
assertFeeRateEqual(startFeeRate)
|
||||
|
||||
// testFeeRate sepcifies a starting fee rate in sat/vbyte.
|
||||
const testFeeRate = uint64(100)
|
||||
|
||||
// Second bump request - we will specify the fee rate and expect a fee
|
||||
// func that has,
|
||||
// - starting fee rate: 100 sat/vbyte.
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 50% of the input value.
|
||||
bumpFeeReq = &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
SatPerVbyte: testFeeRate,
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Alice's old sweeping tx should be replaced.
|
||||
ht.Miner.AssertTxNotInMempool(sweepTx1.TxHash())
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 2.
|
||||
// - starting fee rate: 100 sat/vbyte.
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 50% of the input value.
|
||||
sweepTx2 := assertPendingSweepResp(
|
||||
2, uint64(value/2), deadline, testFeeRate,
|
||||
)
|
||||
|
||||
// We expect the requested starting fee rate to be the current fee
|
||||
// rate.
|
||||
assertFeeRateEqual(testFeeRate)
|
||||
|
||||
// testBudget specifies a budget in sats.
|
||||
testBudget := uint64(float64(value) * 0.1)
|
||||
|
||||
// Third bump request - we will specify the budget and expect a fee
|
||||
// func that has,
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 10% of the input value.
|
||||
bumpFeeReq = &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
Budget: testBudget,
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Alice's old sweeping tx should be replaced.
|
||||
ht.Miner.AssertTxNotInMempool(sweepTx2.TxHash())
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 3.
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 1008 (default deadline).
|
||||
// - budget: 10% of the input value.
|
||||
sweepTx3 := assertPendingSweepResp(3, testBudget, deadline, 0)
|
||||
|
||||
// We expect the current fee rate to be increased because we ensure the
|
||||
// initial broadcast always succeeds.
|
||||
assertFeeRateGreater(testFeeRate)
|
||||
|
||||
// Create a test deadline delta to use in the next test.
|
||||
testDeadlineDelta := uint32(100)
|
||||
deadlineHeight := uint32(currentHeight) + testDeadlineDelta
|
||||
|
||||
// Fourth bump request - we will specify the deadline and expect a fee
|
||||
// func that has,
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 100.
|
||||
// - budget: 10% of the input value, stays unchanged.
|
||||
bumpFeeReq = &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
TargetConf: testDeadlineDelta,
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Alice's old sweeping tx should be replaced.
|
||||
ht.Miner.AssertTxNotInMempool(sweepTx3.TxHash())
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 4.
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 100.
|
||||
// - budget: 10% of the input value, stays unchanged.
|
||||
sweepTx4 := assertPendingSweepResp(4, testBudget, deadlineHeight, 0)
|
||||
|
||||
// We expect the current fee rate to be increased because we ensure the
|
||||
// initial broadcast always succeeds.
|
||||
assertFeeRateGreater(testFeeRate)
|
||||
|
||||
// Fifth bump request - we test the behavior of `Immediate` - every
|
||||
// time it's called, the fee function will keep increasing the fee rate
|
||||
// until the broadcast can succeed. The fee func that has,
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 100, stays unchanged.
|
||||
// - budget: 10% of the input value, stays unchanged.
|
||||
bumpFeeReq = &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Alice's old sweeping tx should be replaced.
|
||||
ht.Miner.AssertTxNotInMempool(sweepTx4.TxHash())
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 5.
|
||||
// - starting fee rate: 100 sat/vbyte, stays unchanged.
|
||||
// - deadline: 100, stays unchanged.
|
||||
// - budget: 10% of the input value, stays unchanged.
|
||||
sweepTx5 := assertPendingSweepResp(5, testBudget, deadlineHeight, 0)
|
||||
|
||||
// We expect the current fee rate to be increased because we ensure the
|
||||
// initial broadcast always succeeds.
|
||||
assertFeeRateGreater(testFeeRate)
|
||||
|
||||
smallBudget := uint64(1000)
|
||||
|
||||
// Finally, we test the behavior of lowering the fee rate. The fee func
|
||||
// that has,
|
||||
// - starting fee rate: 1 sat/vbyte.
|
||||
// - deadline: 1008.
|
||||
// - budget: 1000 sats.
|
||||
bumpFeeReq = &walletrpc.BumpFeeRequest{
|
||||
Outpoint: op,
|
||||
// We use a force param to create the sweeping tx immediately.
|
||||
Immediate: true,
|
||||
SatPerVbyte: startFeeRate,
|
||||
Budget: smallBudget,
|
||||
TargetConf: uint32(sweep.DefaultDeadlineDelta),
|
||||
}
|
||||
alice.RPC.BumpFee(bumpFeeReq)
|
||||
|
||||
// Assert the pending sweep is created with the expected values:
|
||||
// - broadcast attempts: 6.
|
||||
// - starting fee rate: 1 sat/vbyte.
|
||||
// - deadline: 1008.
|
||||
// - budget: 1000 sats.
|
||||
sweepTx6 := assertPendingSweepResp(
|
||||
6, smallBudget, deadline, startFeeRate,
|
||||
)
|
||||
|
||||
// Since this budget is too small to cover the RBF, we expect the
|
||||
// sweeping attempt to fail.
|
||||
//
|
||||
require.Equal(ht, sweepTx5.TxHash(), sweepTx6.TxHash(), "tx5 should "+
|
||||
"not be replaced: tx5=%v, tx6=%v", sweepTx5.TxHash(),
|
||||
sweepTx6.TxHash())
|
||||
|
||||
// We expect the current fee rate to be increased because we ensure the
|
||||
// initial broadcast always succeeds.
|
||||
assertFeeRateGreater(testFeeRate)
|
||||
|
||||
// Clean up the mempol.
|
||||
ht.MineBlocksAndAssertNumTxes(1, 2)
|
||||
}
|
||||
|
@ -2289,3 +2289,27 @@ func (h *HarnessTest) GetOutputIndex(txid *chainhash.Hash, addr string) int {
|
||||
|
||||
return p2trOutputIndex
|
||||
}
|
||||
|
||||
// SendCoins sends a coin from node A to node B with the given amount, returns
|
||||
// the sending tx.
|
||||
func (h *HarnessTest) SendCoins(a, b *node.HarnessNode,
|
||||
amt btcutil.Amount) *wire.MsgTx {
|
||||
|
||||
// Create an address for Bob receive the coins.
|
||||
req := &lnrpc.NewAddressRequest{
|
||||
Type: lnrpc.AddressType_TAPROOT_PUBKEY,
|
||||
}
|
||||
resp := b.RPC.NewAddress(req)
|
||||
|
||||
// Send the coins from Alice to Bob. We should expect a tx to be
|
||||
// broadcast and seen in the mempool.
|
||||
sendReq := &lnrpc.SendCoinsRequest{
|
||||
Addr: resp.Address,
|
||||
Amount: int64(amt),
|
||||
TargetConf: 6,
|
||||
}
|
||||
a.RPC.SendCoins(sendReq)
|
||||
tx := h.Miner.GetNumTxsFromMempool(1)[0]
|
||||
|
||||
return tx
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user