itest: refactor testAnchorReservedValue

This commit is contained in:
yyforyongyu 2022-08-07 05:50:49 +08:00
parent f1f3d22a81
commit 211dad1574
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868
3 changed files with 55 additions and 132 deletions

View File

@ -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,
},
} }

View File

@ -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.

View File

@ -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,