lntest: move multi-hop root test case and common utils to own file
This commit is contained in:
parent
1ade912361
commit
b4ea34037a
@ -5,11 +5,9 @@ package itest
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd"
|
"github.com/lightningnetwork/lnd"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
@ -19,103 +17,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) {
|
|
||||||
|
|
||||||
type testCase struct {
|
|
||||||
name string
|
|
||||||
test func(net *lntest.NetworkHarness, t *harnessTest, alice,
|
|
||||||
bob *lntest.HarnessNode, c commitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
subTests := []testCase{
|
|
||||||
{
|
|
||||||
// bob: outgoing our commit timeout
|
|
||||||
// carol: incoming their commit watch and see timeout
|
|
||||||
name: "local force close immediate expiry",
|
|
||||||
test: testMultiHopHtlcLocalTimeout,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// bob: outgoing watch and see, they sweep on chain
|
|
||||||
// carol: incoming our commit, know preimage
|
|
||||||
name: "receiver chain claim",
|
|
||||||
test: testMultiHopReceiverChainClaim,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// bob: outgoing our commit watch and see timeout
|
|
||||||
// carol: incoming their commit watch and see timeout
|
|
||||||
name: "local force close on-chain htlc timeout",
|
|
||||||
test: testMultiHopLocalForceCloseOnChainHtlcTimeout,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// bob: outgoing their commit watch and see timeout
|
|
||||||
// carol: incoming our commit watch and see timeout
|
|
||||||
name: "remote force close on-chain htlc timeout",
|
|
||||||
test: testMultiHopRemoteForceCloseOnChainHtlcTimeout,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// bob: outgoing our commit watch and see, they sweep on chain
|
|
||||||
// bob: incoming our commit watch and learn preimage
|
|
||||||
// carol: incoming their commit know preimage
|
|
||||||
name: "local chain claim",
|
|
||||||
test: testMultiHopHtlcLocalChainClaim,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// bob: outgoing their commit watch and see, they sweep on chain
|
|
||||||
// bob: incoming their commit watch and learn preimage
|
|
||||||
// carol: incoming our commit know preimage
|
|
||||||
name: "remote chain claim",
|
|
||||||
test: testMultiHopHtlcRemoteChainClaim,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
commitTypes := []commitType{
|
|
||||||
commitTypeLegacy,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, commitType := range commitTypes {
|
|
||||||
testName := fmt.Sprintf("committype=%v", commitType.String())
|
|
||||||
|
|
||||||
success := t.t.Run(testName, func(t *testing.T) {
|
|
||||||
ht := newHarnessTest(t, net)
|
|
||||||
|
|
||||||
args := commitType.Args()
|
|
||||||
alice, err := net.NewNode("Alice", args)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create new node: %v", err)
|
|
||||||
}
|
|
||||||
defer shutdownAndAssert(net, ht, alice)
|
|
||||||
|
|
||||||
bob, err := net.NewNode("Bob", args)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create new node: %v", err)
|
|
||||||
}
|
|
||||||
defer shutdownAndAssert(net, ht, bob)
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
if err := net.ConnectNodes(ctxt, alice, bob); err != nil {
|
|
||||||
t.Fatalf("unable to connect alice to bob: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subTest := range subTests {
|
|
||||||
subTest := subTest
|
|
||||||
|
|
||||||
success := ht.t.Run(subTest.name, func(t *testing.T) {
|
|
||||||
ht := newHarnessTest(t, net)
|
|
||||||
|
|
||||||
subTest.test(net, ht, alice, bob, commitType)
|
|
||||||
})
|
|
||||||
if !success {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if !success {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// testMultiHopHtlcLocalChainClaim tests that in a multi-hop HTLC scenario, if
|
// testMultiHopHtlcLocalChainClaim tests that in a multi-hop HTLC scenario, if
|
||||||
// we force close a channel with an incoming HTLC, and later find out the
|
// we force close a channel with an incoming HTLC, and later find out the
|
||||||
// preimage via the witness beacon, we properly settle the HTLC on-chain using
|
// preimage via the witness beacon, we properly settle the HTLC on-chain using
|
||||||
@ -518,175 +419,3 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitForInvoiceAccepted waits until the specified invoice moved to the
|
|
||||||
// accepted state by the node.
|
|
||||||
func waitForInvoiceAccepted(t *harnessTest, node *lntest.HarnessNode,
|
|
||||||
payHash lntypes.Hash) {
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
invoiceUpdates, err := node.SubscribeSingleInvoice(ctx,
|
|
||||||
&invoicesrpc.SubscribeSingleInvoiceRequest{
|
|
||||||
RHash: payHash[:],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("subscribe single invoice: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
update, err := invoiceUpdates.Recv()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("invoice update err: %v", err)
|
|
||||||
}
|
|
||||||
if update.State == lnrpc.Invoice_ACCEPTED {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkPaymentStatus asserts that the given node list a payment with the given
|
|
||||||
// preimage has the expected status.
|
|
||||||
func checkPaymentStatus(ctxt context.Context, node *lntest.HarnessNode,
|
|
||||||
preimage lntypes.Preimage, status lnrpc.Payment_PaymentStatus) error {
|
|
||||||
|
|
||||||
req := &lnrpc.ListPaymentsRequest{
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
}
|
|
||||||
paymentsResp, err := node.ListPayments(ctxt, req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error when obtaining Alice payments: %v",
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
payHash := preimage.Hash()
|
|
||||||
var found bool
|
|
||||||
for _, p := range paymentsResp.Payments {
|
|
||||||
if p.PaymentHash != payHash.String() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true
|
|
||||||
if p.Status != status {
|
|
||||||
return fmt.Errorf("expected payment status "+
|
|
||||||
"%v, got %v", status, p.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch status {
|
|
||||||
|
|
||||||
// If this expected status is SUCCEEDED, we expect the final preimage.
|
|
||||||
case lnrpc.Payment_SUCCEEDED:
|
|
||||||
if p.PaymentPreimage != preimage.String() {
|
|
||||||
return fmt.Errorf("preimage doesn't match: %v vs %v",
|
|
||||||
p.PaymentPreimage, preimage.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we expect an all-zero preimage.
|
|
||||||
default:
|
|
||||||
if p.PaymentPreimage != (lntypes.Preimage{}).String() {
|
|
||||||
return fmt.Errorf("expected zero preimage, got %v",
|
|
||||||
p.PaymentPreimage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("payment with payment hash %v not found "+
|
|
||||||
"in response", payHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness,
|
|
||||||
alice, bob *lntest.HarnessNode, carolHodl bool, c commitType) (
|
|
||||||
*lnrpc.ChannelPoint, *lnrpc.ChannelPoint, *lntest.HarnessNode) {
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err := net.EnsureConnected(ctxt, alice, bob)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to connect peers: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(context.Background(), defaultTimeout)
|
|
||||||
err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, alice)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to send coins to Alice: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(context.Background(), defaultTimeout)
|
|
||||||
err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, bob)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to send coins to Bob: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll start the test by creating a channel between Alice and Bob,
|
|
||||||
// which will act as the first leg for out multi-hop HTLC.
|
|
||||||
const chanAmt = 1000000
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
|
|
||||||
aliceChanPoint := openChannelAndAssert(
|
|
||||||
ctxt, t, net, alice, bob,
|
|
||||||
lntest.OpenChannelParams{
|
|
||||||
Amt: chanAmt,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err = alice.WaitForNetworkChannelOpen(ctxt, aliceChanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("alice didn't report channel: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err = bob.WaitForNetworkChannelOpen(ctxt, aliceChanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bob didn't report channel: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, we'll create a new node "carol" and have Bob connect to her. If
|
|
||||||
// the carolHodl flag is set, we'll make carol always hold onto the
|
|
||||||
// HTLC, this way it'll force Bob to go to chain to resolve the HTLC.
|
|
||||||
carolFlags := c.Args()
|
|
||||||
if carolHodl {
|
|
||||||
carolFlags = append(carolFlags, "--hodl.exit-settle")
|
|
||||||
}
|
|
||||||
carol, err := net.NewNode("Carol", carolFlags)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create new node: %v", err)
|
|
||||||
}
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
if err := net.ConnectNodes(ctxt, bob, carol); err != nil {
|
|
||||||
t.Fatalf("unable to connect bob to carol: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll then create a channel from Bob to Carol. After this channel is
|
|
||||||
// open, our topology looks like: A -> B -> C.
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
|
|
||||||
bobChanPoint := openChannelAndAssert(
|
|
||||||
ctxt, t, net, bob, carol,
|
|
||||||
lntest.OpenChannelParams{
|
|
||||||
Amt: chanAmt,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err = bob.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("alice didn't report channel: %v", err)
|
|
||||||
}
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err = carol.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bob didn't report channel: %v", err)
|
|
||||||
}
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
err = alice.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bob didn't report channel: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return aliceChanPoint, bobChanPoint, carol
|
|
||||||
}
|
|
||||||
|
284
lntest/itest/lnd_multi-hop_test.go
Normal file
284
lntest/itest/lnd_multi-hop_test.go
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
// +build rpctest
|
||||||
|
|
||||||
|
package itest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
name string
|
||||||
|
test func(net *lntest.NetworkHarness, t *harnessTest, alice,
|
||||||
|
bob *lntest.HarnessNode, c commitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
subTests := []testCase{
|
||||||
|
{
|
||||||
|
// bob: outgoing our commit timeout
|
||||||
|
// carol: incoming their commit watch and see timeout
|
||||||
|
name: "local force close immediate expiry",
|
||||||
|
test: testMultiHopHtlcLocalTimeout,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bob: outgoing watch and see, they sweep on chain
|
||||||
|
// carol: incoming our commit, know preimage
|
||||||
|
name: "receiver chain claim",
|
||||||
|
test: testMultiHopReceiverChainClaim,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bob: outgoing our commit watch and see timeout
|
||||||
|
// carol: incoming their commit watch and see timeout
|
||||||
|
name: "local force close on-chain htlc timeout",
|
||||||
|
test: testMultiHopLocalForceCloseOnChainHtlcTimeout,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bob: outgoing their commit watch and see timeout
|
||||||
|
// carol: incoming our commit watch and see timeout
|
||||||
|
name: "remote force close on-chain htlc timeout",
|
||||||
|
test: testMultiHopRemoteForceCloseOnChainHtlcTimeout,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bob: outgoing our commit watch and see, they sweep on chain
|
||||||
|
// bob: incoming our commit watch and learn preimage
|
||||||
|
// carol: incoming their commit know preimage
|
||||||
|
name: "local chain claim",
|
||||||
|
test: testMultiHopHtlcLocalChainClaim,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bob: outgoing their commit watch and see, they sweep on chain
|
||||||
|
// bob: incoming their commit watch and learn preimage
|
||||||
|
// carol: incoming our commit know preimage
|
||||||
|
name: "remote chain claim",
|
||||||
|
test: testMultiHopHtlcRemoteChainClaim,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
commitTypes := []commitType{
|
||||||
|
commitTypeLegacy,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, commitType := range commitTypes {
|
||||||
|
testName := fmt.Sprintf("committype=%v", commitType.String())
|
||||||
|
|
||||||
|
success := t.t.Run(testName, func(t *testing.T) {
|
||||||
|
ht := newHarnessTest(t, net)
|
||||||
|
|
||||||
|
args := commitType.Args()
|
||||||
|
alice, err := net.NewNode("Alice", args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, ht, alice)
|
||||||
|
|
||||||
|
bob, err := net.NewNode("Bob", args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, ht, bob)
|
||||||
|
|
||||||
|
ctxb := context.Background()
|
||||||
|
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
if err := net.ConnectNodes(ctxt, alice, bob); err != nil {
|
||||||
|
t.Fatalf("unable to connect alice to bob: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subTest := range subTests {
|
||||||
|
subTest := subTest
|
||||||
|
|
||||||
|
success := ht.t.Run(subTest.name, func(t *testing.T) {
|
||||||
|
ht := newHarnessTest(t, net)
|
||||||
|
|
||||||
|
subTest.test(net, ht, alice, bob, commitType)
|
||||||
|
})
|
||||||
|
if !success {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if !success {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForInvoiceAccepted waits until the specified invoice moved to the
|
||||||
|
// accepted state by the node.
|
||||||
|
func waitForInvoiceAccepted(t *harnessTest, node *lntest.HarnessNode,
|
||||||
|
payHash lntypes.Hash) {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
invoiceUpdates, err := node.SubscribeSingleInvoice(ctx,
|
||||||
|
&invoicesrpc.SubscribeSingleInvoiceRequest{
|
||||||
|
RHash: payHash[:],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("subscribe single invoice: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
update, err := invoiceUpdates.Recv()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invoice update err: %v", err)
|
||||||
|
}
|
||||||
|
if update.State == lnrpc.Invoice_ACCEPTED {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkPaymentStatus asserts that the given node list a payment with the given
|
||||||
|
// preimage has the expected status.
|
||||||
|
func checkPaymentStatus(ctxt context.Context, node *lntest.HarnessNode,
|
||||||
|
preimage lntypes.Preimage, status lnrpc.Payment_PaymentStatus) error {
|
||||||
|
|
||||||
|
req := &lnrpc.ListPaymentsRequest{
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
}
|
||||||
|
paymentsResp, err := node.ListPayments(ctxt, req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error when obtaining Alice payments: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
payHash := preimage.Hash()
|
||||||
|
var found bool
|
||||||
|
for _, p := range paymentsResp.Payments {
|
||||||
|
if p.PaymentHash != payHash.String() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true
|
||||||
|
if p.Status != status {
|
||||||
|
return fmt.Errorf("expected payment status "+
|
||||||
|
"%v, got %v", status, p.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
|
||||||
|
// If this expected status is SUCCEEDED, we expect the final preimage.
|
||||||
|
case lnrpc.Payment_SUCCEEDED:
|
||||||
|
if p.PaymentPreimage != preimage.String() {
|
||||||
|
return fmt.Errorf("preimage doesn't match: %v vs %v",
|
||||||
|
p.PaymentPreimage, preimage.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we expect an all-zero preimage.
|
||||||
|
default:
|
||||||
|
if p.PaymentPreimage != (lntypes.Preimage{}).String() {
|
||||||
|
return fmt.Errorf("expected zero preimage, got %v",
|
||||||
|
p.PaymentPreimage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("payment with payment hash %v not found "+
|
||||||
|
"in response", payHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness,
|
||||||
|
alice, bob *lntest.HarnessNode, carolHodl bool, c commitType) (
|
||||||
|
*lnrpc.ChannelPoint, *lnrpc.ChannelPoint, *lntest.HarnessNode) {
|
||||||
|
|
||||||
|
ctxb := context.Background()
|
||||||
|
|
||||||
|
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err := net.EnsureConnected(ctxt, alice, bob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to connect peers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, alice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send coins to Alice: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, bob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send coins to Bob: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll start the test by creating a channel between Alice and Bob,
|
||||||
|
// which will act as the first leg for out multi-hop HTLC.
|
||||||
|
const chanAmt = 1000000
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
|
||||||
|
aliceChanPoint := openChannelAndAssert(
|
||||||
|
ctxt, t, net, alice, bob,
|
||||||
|
lntest.OpenChannelParams{
|
||||||
|
Amt: chanAmt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err = alice.WaitForNetworkChannelOpen(ctxt, aliceChanPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice didn't report channel: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err = bob.WaitForNetworkChannelOpen(ctxt, aliceChanPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob didn't report channel: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, we'll create a new node "carol" and have Bob connect to her. If
|
||||||
|
// the carolHodl flag is set, we'll make carol always hold onto the
|
||||||
|
// HTLC, this way it'll force Bob to go to chain to resolve the HTLC.
|
||||||
|
carolFlags := c.Args()
|
||||||
|
if carolHodl {
|
||||||
|
carolFlags = append(carolFlags, "--hodl.exit-settle")
|
||||||
|
}
|
||||||
|
carol, err := net.NewNode("Carol", carolFlags)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
if err := net.ConnectNodes(ctxt, bob, carol); err != nil {
|
||||||
|
t.Fatalf("unable to connect bob to carol: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll then create a channel from Bob to Carol. After this channel is
|
||||||
|
// open, our topology looks like: A -> B -> C.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
|
||||||
|
bobChanPoint := openChannelAndAssert(
|
||||||
|
ctxt, t, net, bob, carol,
|
||||||
|
lntest.OpenChannelParams{
|
||||||
|
Amt: chanAmt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err = bob.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice didn't report channel: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err = carol.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob didn't report channel: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
err = alice.WaitForNetworkChannelOpen(ctxt, bobChanPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob didn't report channel: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return aliceChanPoint, bobChanPoint, carol
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user