mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
itest: refactor testAnchorReservedValue
This commit is contained in:
parent
f1f3d22a81
commit
211dad1574
@ -263,4 +263,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "multi-hop payments",
|
Name: "multi-hop payments",
|
||||||
TestFunc: testMultiHopPayments,
|
TestFunc: testMultiHopPayments,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "anchors reserved value",
|
||||||
|
TestFunc: testAnchorReservedValue,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
@ -233,17 +232,17 @@ func runCPFP(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// testAnchorReservedValue tests that we won't allow sending transactions when
|
// testAnchorReservedValue tests that we won't allow sending transactions when
|
||||||
// that would take the value we reserve for anchor fee bumping out of our
|
// that would take the value we reserve for anchor fee bumping out of our
|
||||||
// wallet.
|
// wallet.
|
||||||
func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) {
|
func testAnchorReservedValue(ht *lntemp.HarnessTest) {
|
||||||
// Start two nodes supporting anchor channels.
|
// Start two nodes supporting anchor channels.
|
||||||
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
|
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
|
||||||
alice := net.NewNode(t.t, "Alice", args)
|
|
||||||
defer shutdownAndAssert(net, t, alice)
|
|
||||||
|
|
||||||
bob := net.NewNode(t.t, "Bob", args)
|
// NOTE: we cannot reuse the standby node here as the test requires the
|
||||||
defer shutdownAndAssert(net, t, bob)
|
// node to start with no UTXOs.
|
||||||
|
alice := ht.NewNode("Alice", args)
|
||||||
|
bob := ht.Bob
|
||||||
|
ht.RestartNodeWithExtraArgs(bob, args)
|
||||||
|
|
||||||
ctxb := context.Background()
|
ht.ConnectNodes(alice, bob)
|
||||||
net.ConnectNodes(t.t, alice, bob)
|
|
||||||
|
|
||||||
// Send just enough coins for Alice to open a channel without a change
|
// Send just enough coins for Alice to open a channel without a change
|
||||||
// output.
|
// output.
|
||||||
@ -252,100 +251,73 @@ func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
feeEst = 8000
|
feeEst = 8000
|
||||||
)
|
)
|
||||||
|
|
||||||
net.SendCoins(t.t, chanAmt+feeEst, alice)
|
ht.FundCoins(chanAmt+feeEst, alice)
|
||||||
|
|
||||||
// wallet, without a change output. This should not be allowed.
|
// wallet, without a change output. This should not be allowed.
|
||||||
resErr := lnwallet.ErrReservedValueInvalidated.Error()
|
ht.OpenChannelAssertErr(
|
||||||
|
alice, bob, lntemp.OpenChannelParams{
|
||||||
_, err := net.OpenChannel(
|
|
||||||
alice, bob, lntest.OpenChannelParams{
|
|
||||||
Amt: chanAmt,
|
Amt: chanAmt,
|
||||||
},
|
}, lnwallet.ErrReservedValueInvalidated,
|
||||||
)
|
)
|
||||||
if err == nil || !strings.Contains(err.Error(), resErr) {
|
|
||||||
t.Fatalf("expected failure, got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alice opens a smaller channel. This works since it will have a
|
// Alice opens a smaller channel. This works since it will have a
|
||||||
// change output.
|
// change output.
|
||||||
aliceChanPoint1 := openChannelAndAssert(
|
chanPoint1 := ht.OpenChannel(
|
||||||
t, net, alice, bob, lntest.OpenChannelParams{
|
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4},
|
||||||
Amt: chanAmt / 4,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// If Alice tries to open another anchor channel to Bob, Bob should not
|
// If Alice tries to open another anchor channel to Bob, Bob should not
|
||||||
// reject it as he is not contributing any funds.
|
// reject it as he is not contributing any funds.
|
||||||
aliceChanPoint2 := openChannelAndAssert(
|
chanPoint2 := ht.OpenChannel(
|
||||||
t, net, alice, bob, lntest.OpenChannelParams{
|
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4},
|
||||||
Amt: chanAmt / 4,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Similarly, if Alice tries to open a legacy channel to Bob, Bob should
|
// Similarly, if Alice tries to open a legacy channel to Bob, Bob
|
||||||
// not reject it as he is not contributing any funds. We'll restart Bob
|
// should not reject it as he is not contributing any funds. We'll
|
||||||
// to remove his support for anchors.
|
// restart Bob to remove his support for anchors.
|
||||||
err = net.RestartNode(bob, nil)
|
ht.RestartNode(bob)
|
||||||
require.NoError(t.t, err)
|
|
||||||
aliceChanPoint3 := openChannelAndAssert(
|
// Before opening the channel, make sure the nodes are connected.
|
||||||
t, net, alice, bob, lntest.OpenChannelParams{
|
ht.EnsureConnected(alice, bob)
|
||||||
Amt: chanAmt / 4,
|
|
||||||
},
|
chanPoint3 := ht.OpenChannel(
|
||||||
|
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4},
|
||||||
)
|
)
|
||||||
|
chanPoints := []*lnrpc.ChannelPoint{chanPoint1, chanPoint2, chanPoint3}
|
||||||
chanPoints := []*lnrpc.ChannelPoint{
|
|
||||||
aliceChanPoint1, aliceChanPoint2, aliceChanPoint3,
|
|
||||||
}
|
|
||||||
for _, chanPoint := range chanPoints {
|
|
||||||
err = alice.WaitForNetworkChannelOpen(chanPoint)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
err = bob.WaitForNetworkChannelOpen(chanPoint)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alice tries to send all coins to an internal address. This is
|
// Alice tries to send all coins to an internal address. This is
|
||||||
// allowed, since the final wallet balance will still be above the
|
// allowed, since the final wallet balance will still be above the
|
||||||
// reserved value.
|
// reserved value.
|
||||||
addrReq := &lnrpc.NewAddressRequest{
|
req := &lnrpc.NewAddressRequest{
|
||||||
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
|
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
|
||||||
}
|
}
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
resp := alice.RPC.NewAddress(req)
|
||||||
resp, err := alice.NewAddress(ctxt, addrReq)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
sweepReq := &lnrpc.SendCoinsRequest{
|
sweepReq := &lnrpc.SendCoinsRequest{
|
||||||
Addr: resp.Address,
|
Addr: resp.Address,
|
||||||
SendAll: true,
|
SendAll: true,
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
alice.RPC.SendCoins(sweepReq)
|
||||||
_, err = alice.SendCoins(ctxt, sweepReq)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
block := mineBlocks(t, net, 1, 1)[0]
|
block := ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
|
|
||||||
|
assertNumTxInAndTxOut := func(tx *wire.MsgTx, in, out int) {
|
||||||
|
require.Len(ht, tx.TxIn, in, "num inputs not matched")
|
||||||
|
require.Len(ht, tx.TxOut, out, "num outputs not matched")
|
||||||
|
}
|
||||||
|
|
||||||
// The sweep transaction should have exactly one input, the change from
|
// The sweep transaction should have exactly one input, the change from
|
||||||
// the previous SendCoins call.
|
// the previous SendCoins call.
|
||||||
sweepTx := block.Transactions[1]
|
sweepTx := block.Transactions[1]
|
||||||
if len(sweepTx.TxIn) != 1 {
|
|
||||||
t.Fatalf("expected 1 inputs instead have %v", len(sweepTx.TxIn))
|
|
||||||
}
|
|
||||||
|
|
||||||
// It should have a single output.
|
// It should have a single output.
|
||||||
if len(sweepTx.TxOut) != 1 {
|
assertNumTxInAndTxOut(sweepTx, 1, 1)
|
||||||
t.Fatalf("expected 1 output instead have %v", len(sweepTx.TxOut))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for Alice to see her balance as confirmed.
|
// Wait for Alice to see her balance as confirmed.
|
||||||
waitForConfirmedBalance := func() int64 {
|
waitForConfirmedBalance := func() int64 {
|
||||||
var balance int64
|
var balance int64
|
||||||
err := wait.NoError(func() error {
|
err := wait.NoError(func() error {
|
||||||
req := &lnrpc.WalletBalanceRequest{}
|
resp := alice.RPC.WalletBalance()
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
resp, err := alice.WalletBalance(ctxt, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.TotalBalance == 0 {
|
if resp.TotalBalance == 0 {
|
||||||
return fmt.Errorf("no balance")
|
return fmt.Errorf("no balance")
|
||||||
@ -358,93 +330,51 @@ func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
balance = resp.TotalBalance
|
balance = resp.TotalBalance
|
||||||
return nil
|
return nil
|
||||||
}, defaultTimeout)
|
}, defaultTimeout)
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err, "timeout checking alice's balance")
|
||||||
|
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = waitForConfirmedBalance()
|
waitForConfirmedBalance()
|
||||||
|
|
||||||
// Alice tries to send all funds to an external address, the reserved
|
// Alice tries to send all funds to an external address, the reserved
|
||||||
// value must stay in her wallet.
|
// value must stay in her wallet.
|
||||||
minerAddr, err := net.Miner.NewAddress()
|
minerAddr := ht.Miner.NewMinerAddress()
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
sweepReq = &lnrpc.SendCoinsRequest{
|
sweepReq = &lnrpc.SendCoinsRequest{
|
||||||
Addr: minerAddr.String(),
|
Addr: minerAddr.String(),
|
||||||
SendAll: true,
|
SendAll: true,
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
alice.RPC.SendCoins(sweepReq)
|
||||||
_, err = alice.SendCoins(ctxt, sweepReq)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
// We'll mine a block which should include the sweep transaction we
|
// We'll mine a block which should include the sweep transaction we
|
||||||
// generated above.
|
// generated above.
|
||||||
block = mineBlocks(t, net, 1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
|
|
||||||
// The sweep transaction should have exactly one inputs as we only had
|
// The sweep transaction should have exactly one inputs as we only had
|
||||||
// the single output from above in the wallet.
|
// the single output from above in the wallet.
|
||||||
sweepTx = block.Transactions[1]
|
sweepTx = block.Transactions[1]
|
||||||
if len(sweepTx.TxIn) != 1 {
|
|
||||||
t.Fatalf("expected 1 inputs instead have %v", len(sweepTx.TxIn))
|
|
||||||
}
|
|
||||||
|
|
||||||
// It should have two outputs, one being the miner address, the other
|
// It should have two outputs, one being the miner address, the other
|
||||||
// one being the reserve going back to our wallet.
|
// one being the reserve going back to our wallet.
|
||||||
if len(sweepTx.TxOut) != 2 {
|
assertNumTxInAndTxOut(sweepTx, 1, 2)
|
||||||
t.Fatalf("expected 2 outputs instead have %v", len(sweepTx.TxOut))
|
|
||||||
}
|
|
||||||
|
|
||||||
// The reserved value is now back in Alice's wallet.
|
// The reserved value is now back in Alice's wallet.
|
||||||
aliceBalance := waitForConfirmedBalance()
|
aliceBalance := waitForConfirmedBalance()
|
||||||
|
|
||||||
// The reserved value should be equal to the required reserve for anchor
|
|
||||||
// channels.
|
|
||||||
walletBalanceResp, err := alice.WalletBalance(
|
|
||||||
ctxb, &lnrpc.WalletBalanceRequest{},
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
require.Equal(
|
|
||||||
t.t, aliceBalance, walletBalanceResp.ReservedBalanceAnchorChan,
|
|
||||||
)
|
|
||||||
|
|
||||||
additionalChannels := int64(1)
|
|
||||||
|
|
||||||
// Required reserve when additional channels are provided.
|
|
||||||
requiredReserveResp, err := alice.WalletKitClient.RequiredReserve(
|
|
||||||
ctxb, &walletrpc.RequiredReserveRequest{
|
|
||||||
AdditionalPublicChannels: uint32(additionalChannels),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
additionalReservedValue := btcutil.Amount(additionalChannels *
|
|
||||||
int64(lnwallet.AnchorChanReservedValue))
|
|
||||||
totalReserved := btcutil.Amount(aliceBalance) + additionalReservedValue
|
|
||||||
|
|
||||||
// The total reserved value should not exceed the maximum value reserved
|
|
||||||
// for anchor channels.
|
|
||||||
if totalReserved > lnwallet.MaxAnchorChanReservedValue {
|
|
||||||
totalReserved = lnwallet.MaxAnchorChanReservedValue
|
|
||||||
}
|
|
||||||
require.Equal(
|
|
||||||
t.t, int64(totalReserved), requiredReserveResp.RequiredReserve,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Alice closes channel, should now be allowed to send everything to an
|
// Alice closes channel, should now be allowed to send everything to an
|
||||||
// external address.
|
// external address.
|
||||||
for _, chanPoint := range chanPoints {
|
for _, chanPoint := range chanPoints {
|
||||||
closeChannelAndAssert(t, net, alice, chanPoint, false)
|
ht.CloseChannel(alice, chanPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
newBalance := waitForConfirmedBalance()
|
newBalance := waitForConfirmedBalance()
|
||||||
if newBalance <= aliceBalance {
|
require.Greater(ht, newBalance, aliceBalance,
|
||||||
t.Fatalf("Alice's balance did not increase after channel close")
|
"Alice's balance did not increase after channel close")
|
||||||
}
|
|
||||||
|
|
||||||
// Assert there are no open or pending channels anymore.
|
// Assert there are no open or pending channels anymore.
|
||||||
assertNumPendingChannels(t, alice, 0, 0)
|
ht.AssertNumWaitingClose(alice, 0)
|
||||||
assertNodeNumChannels(t, alice, 0)
|
ht.AssertNodeNumChannels(alice, 0)
|
||||||
|
|
||||||
// We'll wait for the balance to reflect that the channel has been
|
// We'll wait for the balance to reflect that the channel has been
|
||||||
// closed and the funds are in the wallet.
|
// closed and the funds are in the wallet.
|
||||||
@ -452,25 +382,18 @@ func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
Addr: minerAddr.String(),
|
Addr: minerAddr.String(),
|
||||||
SendAll: true,
|
SendAll: true,
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
alice.RPC.SendCoins(sweepReq)
|
||||||
_, err = alice.SendCoins(ctxt, sweepReq)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
// We'll mine a block which should include the sweep transaction we
|
// We'll mine a block which should include the sweep transaction we
|
||||||
// generated above.
|
// generated above.
|
||||||
block = mineBlocks(t, net, 1, 1)[0]
|
block = ht.MineBlocksAndAssertNumTxes(1, 1)[0]
|
||||||
|
|
||||||
// The sweep transaction should have four inputs, the change output from
|
// The sweep transaction should have four inputs, the change output from
|
||||||
// the previous sweep, and the outputs from the coop closed channels.
|
// the previous sweep, and the outputs from the coop closed channels.
|
||||||
sweepTx = block.Transactions[1]
|
sweepTx = block.Transactions[1]
|
||||||
if len(sweepTx.TxIn) != 4 {
|
|
||||||
t.Fatalf("expected 4 inputs instead have %v", len(sweepTx.TxIn))
|
|
||||||
}
|
|
||||||
|
|
||||||
// It should have a single output.
|
// It should have a single output.
|
||||||
if len(sweepTx.TxOut) != 1 {
|
assertNumTxInAndTxOut(sweepTx, 4, 1)
|
||||||
t.Fatalf("expected 1 output instead have %v", len(sweepTx.TxOut))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// genAnchorSweep generates a "3rd party" anchor sweeping from an existing one.
|
// genAnchorSweep generates a "3rd party" anchor sweeping from an existing one.
|
||||||
|
@ -106,10 +106,6 @@ var allTestCases = []*testCase{
|
|||||||
name: "cpfp",
|
name: "cpfp",
|
||||||
test: testCPFP,
|
test: testCPFP,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "anchors reserved value",
|
|
||||||
test: testAnchorReservedValue,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "macaroon authentication",
|
name: "macaroon authentication",
|
||||||
test: testMacaroonAuthentication,
|
test: testMacaroonAuthentication,
|
||||||
|
Loading…
Reference in New Issue
Block a user