lntemp+itest: remove unused code to prepare lntemp's takeover
This commit removes the old code living in `lntest` to prepare `lntemp`'s takeover.
This commit is contained in:
30 files changed
+305
-6533
No files matched your search
-1357
File diff suppressed because it is too large.
Load diff
@@ -1087,3 +1087,71 @@ func assertReports(ht *lntemp.HarnessTest, hn *node.HarnessNode,
|
|||||||
require.Equal(ht, expected, res)
|
require.Equal(ht, expected, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkCommitmentMaturity checks that both the maturity height and blocks
|
||||||
|
// maturity height are as expected.
|
||||||
|
//
|
||||||
|
// NOTE: only used in current test file.
|
||||||
|
func checkCommitmentMaturity(forceClose lntemp.PendingForceClose,
|
||||||
|
maturityHeight uint32, blocksTilMaturity int32) error {
|
||||||
|
|
||||||
|
if forceClose.MaturityHeight != maturityHeight {
|
||||||
|
return fmt.Errorf("expected commitment maturity height to be "+
|
||||||
|
"%d, found %d instead", maturityHeight,
|
||||||
|
forceClose.MaturityHeight)
|
||||||
|
}
|
||||||
|
if forceClose.BlocksTilMaturity != blocksTilMaturity {
|
||||||
|
return fmt.Errorf("expected commitment blocks til maturity to "+
|
||||||
|
"be %d, found %d instead", blocksTilMaturity,
|
||||||
|
forceClose.BlocksTilMaturity)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkForceClosedChannelNumHtlcs verifies that a force closed channel has the
|
||||||
|
// proper number of htlcs.
|
||||||
|
//
|
||||||
|
// NOTE: only used in current test file.
|
||||||
|
func checkPendingChannelNumHtlcs(
|
||||||
|
forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel,
|
||||||
|
expectedNumHtlcs int) error {
|
||||||
|
|
||||||
|
if len(forceClose.PendingHtlcs) != expectedNumHtlcs {
|
||||||
|
return fmt.Errorf("expected force closed channel to have %d "+
|
||||||
|
"pending htlcs, found %d instead", expectedNumHtlcs,
|
||||||
|
len(forceClose.PendingHtlcs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkPendingHtlcStageAndMaturity uniformly tests all pending htlc's belonging
|
||||||
|
// to a force closed channel, testing for the expected stage number, blocks till
|
||||||
|
// maturity, and the maturity height.
|
||||||
|
//
|
||||||
|
// NOTE: only used in current test file.
|
||||||
|
func checkPendingHtlcStageAndMaturity(
|
||||||
|
forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel,
|
||||||
|
stage, maturityHeight uint32, blocksTillMaturity int32) error {
|
||||||
|
|
||||||
|
for _, pendingHtlc := range forceClose.PendingHtlcs {
|
||||||
|
if pendingHtlc.Stage != stage {
|
||||||
|
return fmt.Errorf("expected pending htlc to be stage "+
|
||||||
|
"%d, found %d", stage, pendingHtlc.Stage)
|
||||||
|
}
|
||||||
|
if pendingHtlc.MaturityHeight != maturityHeight {
|
||||||
|
return fmt.Errorf("expected pending htlc maturity "+
|
||||||
|
"height to be %d, instead has %d",
|
||||||
|
maturityHeight, pendingHtlc.MaturityHeight)
|
||||||
|
}
|
||||||
|
if pendingHtlc.BlocksTilMaturity != blocksTillMaturity {
|
||||||
|
return fmt.Errorf("expected pending htlc blocks til "+
|
||||||
|
"maturity to be %d, instead has %d",
|
||||||
|
blocksTillMaturity,
|
||||||
|
pendingHtlc.BlocksTilMaturity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -12,25 +12,10 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// assertPolicyUpdate checks that a given policy update has been received by a
|
|
||||||
// list of given nodes.
|
|
||||||
// TODO(yy): delete.
|
|
||||||
func assertPolicyUpdate(t *harnessTest, nodes []*lntest.HarnessNode,
|
|
||||||
advertisingNode string, policy *lnrpc.RoutingPolicy,
|
|
||||||
chanPoint *lnrpc.ChannelPoint) {
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
assertChannelPolicyUpdate(
|
|
||||||
t.t, node, advertisingNode, policy, chanPoint, false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// testUpdateChannelPolicy tests that policy updates made to a channel
|
// testUpdateChannelPolicy tests that policy updates made to a channel
|
||||||
// gets propagated to other nodes in the network.
|
// gets propagated to other nodes in the network.
|
||||||
func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
|
func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lncfg"
|
"github.com/lightningnetwork/lnd/lncfg"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ func testEtcdFailover(ht *lntemp.HarnessTest) {
|
|||||||
|
|
||||||
func testEtcdFailoverCase(ht *lntemp.HarnessTest, kill bool) {
|
func testEtcdFailoverCase(ht *lntemp.HarnessTest, kill bool) {
|
||||||
etcdCfg, cleanup, err := kvdb.StartEtcdTestBackend(
|
etcdCfg, cleanup, err := kvdb.StartEtcdTestBackend(
|
||||||
ht.T.TempDir(), uint16(lntest.NextAvailablePort()),
|
ht.T.TempDir(), uint16(node.NextAvailablePort()),
|
||||||
uint16(lntest.NextAvailablePort()), "",
|
uint16(node.NextAvailablePort()), "",
|
||||||
)
|
)
|
||||||
require.NoError(ht, err, "Failed to start etcd instance")
|
require.NoError(ht, err, "Failed to start etcd instance")
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -52,102 +51,6 @@ var commitWithZeroConf = []struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(node *lntest.HarnessNode, preimage lntypes.Preimage,
|
|
||||||
status lnrpc.Payment_PaymentStatus) error {
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// assertAllTxesSpendFrom asserts that all txes in the list spend from the given
|
|
||||||
// tx.
|
|
||||||
func assertAllTxesSpendFrom(t *harnessTest, txes []*wire.MsgTx,
|
|
||||||
prevTxid chainhash.Hash) {
|
|
||||||
|
|
||||||
for _, tx := range txes {
|
|
||||||
if tx.TxIn[0].PreviousOutPoint.Hash != prevTxid {
|
|
||||||
t.Fatalf("tx %v did not spend from %v",
|
|
||||||
tx.TxHash(), prevTxid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// caseRunner defines a single test case runner.
|
// caseRunner defines a single test case runner.
|
||||||
type caseRunner func(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode,
|
type caseRunner func(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode,
|
||||||
c lnrpc.CommitmentType, zeroConf bool)
|
c lnrpc.CommitmentType, zeroConf bool)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -105,7 +104,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
|
|||||||
|
|
||||||
// We derive an extra port for Dave, and we initialise his node with
|
// We derive an extra port for Dave, and we initialise his node with
|
||||||
// the port advertised as `--externalip` arguments.
|
// the port advertised as `--externalip` arguments.
|
||||||
ip2 := lntest.NextAvailablePort()
|
ip2 := node.NextAvailablePort()
|
||||||
|
|
||||||
// Create a new node, Dave, which will initialize a P2P port for him.
|
// Create a new node, Dave, which will initialize a P2P port for him.
|
||||||
daveArgs := []string{fmt.Sprintf("--externalip=127.0.0.1:%d", ip2)}
|
daveArgs := []string{fmt.Sprintf("--externalip=127.0.0.1:%d", ip2)}
|
||||||
@@ -184,7 +183,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
|
|||||||
// address.
|
// address.
|
||||||
|
|
||||||
// Change Dave's listening port and restart.
|
// Change Dave's listening port and restart.
|
||||||
dave.Cfg.P2PPort = lntest.NextAvailablePort()
|
dave.Cfg.P2PPort = node.NextAvailablePort()
|
||||||
dave.Cfg.ExtraArgs = []string{
|
dave.Cfg.ExtraArgs = []string{
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"--externalip=127.0.0.1:%d", dave.Cfg.P2PPort,
|
"--externalip=127.0.0.1:%d", dave.Cfg.P2PPort,
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package itest
|
|||||||
import (
|
import (
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
|
"github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testNeutrino checks that the neutrino sub-server can fetch compact
|
// testNeutrino checks that the neutrino sub-server can fetch compact
|
||||||
// block filters, server status and connect to a connected peer.
|
// block filters, server status and connect to a connected peer.
|
||||||
func testNeutrino(ht *lntemp.HarnessTest) {
|
func testNeutrino(ht *lntemp.HarnessTest) {
|
||||||
if ht.ChainBackendName() != lntest.NeutrinoBackendName {
|
if !ht.IsNeutrinoBackend() {
|
||||||
ht.Skipf("skipping test for non neutrino backends")
|
ht.Skipf("skipping test for non neutrino backends")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1187,60 +1186,6 @@ func deriveInternalKey(ht *lntemp.HarnessTest,
|
|||||||
return keyDesc, parsedPubKey, fullDerivationPath
|
return keyDesc, parsedPubKey, fullDerivationPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// openChannelPsbt attempts to open a channel between srcNode and destNode with
|
|
||||||
// the passed channel funding parameters. If the passed context has a timeout,
|
|
||||||
// then if the timeout is reached before the channel pending notification is
|
|
||||||
// received, an error is returned. An error is returned if the expected step
|
|
||||||
// of funding the PSBT is not received from the source node.
|
|
||||||
func openChannelPsbt(ctx context.Context, srcNode, destNode *lntest.HarnessNode,
|
|
||||||
p lntest.OpenChannelParams) (lnrpc.Lightning_OpenChannelClient, []byte,
|
|
||||||
error) {
|
|
||||||
|
|
||||||
// Wait until srcNode and destNode have the latest chain synced.
|
|
||||||
// Otherwise, we may run into a check within the funding manager that
|
|
||||||
// prevents any funding workflows from being kicked off if the chain
|
|
||||||
// isn't yet synced.
|
|
||||||
if err := srcNode.WaitForBlockchainSync(); err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("unable to sync srcNode chain: %v",
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
if err := destNode.WaitForBlockchainSync(); err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("unable to sync destNode chain: %v",
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the request to open a channel to the source node now. This will
|
|
||||||
// open a long-lived stream where we'll receive status updates about the
|
|
||||||
// progress of the channel.
|
|
||||||
respStream, err := srcNode.OpenChannel(ctx, &lnrpc.OpenChannelRequest{
|
|
||||||
NodePubkey: destNode.PubKey[:],
|
|
||||||
LocalFundingAmount: int64(p.Amt),
|
|
||||||
PushSat: int64(p.PushAmt),
|
|
||||||
Private: p.Private,
|
|
||||||
SpendUnconfirmed: p.SpendUnconfirmed,
|
|
||||||
MinHtlcMsat: int64(p.MinHtlc),
|
|
||||||
FundingShim: p.FundingShim,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("unable to open channel between "+
|
|
||||||
"source and dest: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume the "PSBT funding ready" update. This waits until the node
|
|
||||||
// notifies us that the PSBT can now be funded.
|
|
||||||
resp, err := receiveChanUpdate(ctx, respStream)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("unable to consume channel update "+
|
|
||||||
"message: %v", err)
|
|
||||||
}
|
|
||||||
upd, ok := resp.Update.(*lnrpc.OpenStatusUpdate_PsbtFund)
|
|
||||||
if !ok {
|
|
||||||
return nil, nil, fmt.Errorf("expected PSBT funding update, "+
|
|
||||||
"instead got %v", resp)
|
|
||||||
}
|
|
||||||
return respStream, upd.PsbtFund.Psbt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// receiveChanUpdate waits until a message is received on the stream or the
|
// receiveChanUpdate waits until a message is received on the stream or the
|
||||||
// context is canceled. The context must have a timeout or must be canceled
|
// context is canceled. The context must have a timeout or must be canceled
|
||||||
// in case no message is received, otherwise this function will block forever.
|
// in case no message is received, otherwise this function will block forever.
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -158,7 +157,7 @@ func testRevokedCloseRetribution(ht *lntemp.HarnessTest) {
|
|||||||
// tx's confHeight+CSV-1 blocks and since we've already mined one that
|
// tx's confHeight+CSV-1 blocks and since we've already mined one that
|
||||||
// included the justice tx we only need to mine extra DefaultCSV-2
|
// included the justice tx we only need to mine extra DefaultCSV-2
|
||||||
// blocks to unlock it.
|
// blocks to unlock it.
|
||||||
ht.MineBlocks(lntest.DefaultCSV - 2)
|
ht.MineBlocks(defaultCSV - 2)
|
||||||
|
|
||||||
ht.AssertNumPendingForceClose(bob, 0)
|
ht.AssertNumPendingForceClose(bob, 0)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/grpclog"
|
||||||
)
|
)
|
||||||
@@ -62,7 +62,7 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
|
|
||||||
// Get the test cases to be run in this tranche.
|
// Get the test cases to be run in this tranche.
|
||||||
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
|
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
|
||||||
lntest.ApplyPortOffset(uint32(trancheIndex) * 1000)
|
node.ApplyPortOffset(uint32(trancheIndex) * 1000)
|
||||||
|
|
||||||
// Create a simple fee service.
|
// Create a simple fee service.
|
||||||
feeService := lntemp.NewFeeService(t)
|
feeService := lntemp.NewFeeService(t)
|
||||||
@@ -188,7 +188,7 @@ func init() {
|
|||||||
// Before we start any node, we need to make sure that any btcd node
|
// Before we start any node, we need to make sure that any btcd node
|
||||||
// that is started through the RPC harness uses a unique port as well
|
// that is started through the RPC harness uses a unique port as well
|
||||||
// to avoid any port collisions.
|
// to avoid any port collisions.
|
||||||
rpctest.ListenAddressGenerator = lntest.GenerateBtcdListenerAddresses
|
rpctest.ListenAddressGenerator = node.GenerateBtcdListenerAddresses
|
||||||
|
|
||||||
// Swap out grpc's default logger with out fake logger which drops the
|
// Swap out grpc's default logger with out fake logger which drops the
|
||||||
// statements on the floor.
|
// statements on the floor.
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -893,7 +892,7 @@ func acceptChannel(t *testing.T, zeroConf bool, stream rpc.AcceptorClient) {
|
|||||||
// be deleted from the channel graph. This was previously the case due to logic
|
// be deleted from the channel graph. This was previously the case due to logic
|
||||||
// in the function DisconnectBlockAtHeight.
|
// in the function DisconnectBlockAtHeight.
|
||||||
func testZeroConfReorg(ht *lntemp.HarnessTest) {
|
func testZeroConfReorg(ht *lntemp.HarnessTest) {
|
||||||
if ht.ChainBackendName() == lntest.NeutrinoBackendName {
|
if ht.IsNeutrinoBackend() {
|
||||||
ht.Skipf("skipping zero-conf reorg test for neutrino backend")
|
ht.Skipf("skipping zero-conf reorg test for neutrino backend")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,351 +0,0 @@
|
|||||||
package itest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
"github.com/go-errors/errors"
|
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
harnessNetParams = &chaincfg.RegressionNetParams
|
|
||||||
|
|
||||||
// lndExecutable is the full path to the lnd binary.
|
|
||||||
lndExecutable = flag.String(
|
|
||||||
"lndexec", itestLndBinary, "full path to lnd binary",
|
|
||||||
)
|
|
||||||
|
|
||||||
slowMineDelay = 20 * time.Millisecond
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
testFeeBase = 1e+6
|
|
||||||
defaultCSV = lntest.DefaultCSV
|
|
||||||
defaultTimeout = wait.DefaultTimeout
|
|
||||||
minerMempoolTimeout = wait.MinerMempoolTimeout
|
|
||||||
channelCloseTimeout = wait.ChannelCloseTimeout
|
|
||||||
itestLndBinary = "../../lnd-itest"
|
|
||||||
anchorSize = 330
|
|
||||||
noFeeLimitMsat = math.MaxInt64
|
|
||||||
|
|
||||||
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
|
|
||||||
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
|
|
||||||
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
|
|
||||||
)
|
|
||||||
|
|
||||||
// harnessTest wraps a regular testing.T providing enhanced error detection
|
|
||||||
// and propagation. All error will be augmented with a full stack-trace in
|
|
||||||
// order to aid in debugging. Additionally, any panics caused by active
|
|
||||||
// test cases will also be handled and represented as fatals.
|
|
||||||
type harnessTest struct {
|
|
||||||
t *testing.T
|
|
||||||
|
|
||||||
// testCase is populated during test execution and represents the
|
|
||||||
// current test case.
|
|
||||||
testCase *testCase
|
|
||||||
|
|
||||||
// lndHarness is a reference to the current network harness. Will be
|
|
||||||
// nil if not yet set up.
|
|
||||||
lndHarness *lntest.NetworkHarness
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHarnessTest creates a new instance of a harnessTest from a regular
|
|
||||||
// testing.T instance.
|
|
||||||
func newHarnessTest(t *testing.T, net *lntest.NetworkHarness) *harnessTest {
|
|
||||||
return &harnessTest{t, nil, net}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skipf calls the underlying testing.T's Skip method, causing the current test
|
|
||||||
// to be skipped.
|
|
||||||
func (h *harnessTest) Skipf(format string, args ...interface{}) {
|
|
||||||
h.t.Skipf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf causes the current active test case to fail with a fatal error. All
|
|
||||||
// integration tests should mark test failures solely with this method due to
|
|
||||||
// the error stack traces it produces.
|
|
||||||
func (h *harnessTest) Fatalf(format string, a ...interface{}) {
|
|
||||||
if h.lndHarness != nil {
|
|
||||||
h.lndHarness.SaveProfilesPages(h.t)
|
|
||||||
}
|
|
||||||
|
|
||||||
stacktrace := errors.Wrap(fmt.Sprintf(format, a...), 1).ErrorStack()
|
|
||||||
|
|
||||||
if h.testCase != nil {
|
|
||||||
h.t.Fatalf("Failed: (%v): exited with error: \n"+
|
|
||||||
"%v", h.testCase.name, stacktrace)
|
|
||||||
} else {
|
|
||||||
h.t.Fatalf("Error outside of test: %v", stacktrace)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunTestCase executes a harness test case. Any errors or panics will be
|
|
||||||
// represented as fatal.
|
|
||||||
func (h *harnessTest) RunTestCase(testCase *testCase) {
|
|
||||||
h.testCase = testCase
|
|
||||||
defer func() {
|
|
||||||
h.testCase = nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
description := errors.Wrap(err, 2).ErrorStack()
|
|
||||||
h.t.Fatalf("Failed: (%v) panicked with: \n%v",
|
|
||||||
h.testCase.name, description)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
testCase.test(h.lndHarness, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *harnessTest) Logf(format string, args ...interface{}) {
|
|
||||||
h.t.Logf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *harnessTest) Log(args ...interface{}) {
|
|
||||||
h.t.Log(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *harnessTest) getLndBinary() string {
|
|
||||||
binary := itestLndBinary
|
|
||||||
lndExec := ""
|
|
||||||
if lndExecutable != nil && *lndExecutable != "" {
|
|
||||||
lndExec = *lndExecutable
|
|
||||||
}
|
|
||||||
if lndExec == "" && runtime.GOOS == "windows" {
|
|
||||||
// Windows (even in a bash like environment like git bash as on
|
|
||||||
// Travis) doesn't seem to like relative paths to exe files...
|
|
||||||
currentDir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
h.Fatalf("unable to get working directory: %v", err)
|
|
||||||
}
|
|
||||||
targetPath := filepath.Join(currentDir, "../../lnd-itest.exe")
|
|
||||||
binary, err = filepath.Abs(targetPath)
|
|
||||||
if err != nil {
|
|
||||||
h.Fatalf("unable to get absolute path: %v", err)
|
|
||||||
}
|
|
||||||
} else if lndExec != "" {
|
|
||||||
binary = lndExec
|
|
||||||
}
|
|
||||||
|
|
||||||
return binary
|
|
||||||
}
|
|
||||||
|
|
||||||
type testCase struct {
|
|
||||||
name string
|
|
||||||
test func(net *lntest.NetworkHarness, t *harnessTest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForTxInMempool polls until finding one transaction in the provided
|
|
||||||
// miner's mempool. An error is returned if *one* transaction isn't found within
|
|
||||||
// the given timeout.
|
|
||||||
func waitForTxInMempool(miner *rpcclient.Client,
|
|
||||||
timeout time.Duration) (*chainhash.Hash, error) {
|
|
||||||
|
|
||||||
txs, err := waitForNTxsInMempool(miner, 1, timeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return txs[0], err
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForNTxsInMempool polls until finding the desired number of transactions
|
|
||||||
// in the provided miner's mempool. An error is returned if this number is not
|
|
||||||
// met after the given timeout.
|
|
||||||
func waitForNTxsInMempool(miner *rpcclient.Client, n int,
|
|
||||||
timeout time.Duration) ([]*chainhash.Hash, error) {
|
|
||||||
|
|
||||||
breakTimeout := time.After(timeout)
|
|
||||||
ticker := time.NewTicker(50 * time.Millisecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var mempool []*chainhash.Hash
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-breakTimeout:
|
|
||||||
return nil, fmt.Errorf("wanted %v, found %v txs "+
|
|
||||||
"in mempool: %v", n, len(mempool), mempool)
|
|
||||||
case <-ticker.C:
|
|
||||||
mempool, err = miner.GetRawMempool()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mempool) == n {
|
|
||||||
return mempool, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mineBlocks mine 'num' of blocks and check that blocks are present in
|
|
||||||
// node blockchain. numTxs should be set to the number of transactions
|
|
||||||
// (excluding the coinbase) we expect to be included in the first mined block.
|
|
||||||
func mineBlocksFast(t *harnessTest, net *lntest.NetworkHarness,
|
|
||||||
num uint32, numTxs int) []*wire.MsgBlock {
|
|
||||||
|
|
||||||
// If we expect transactions to be included in the blocks we'll mine,
|
|
||||||
// we wait here until they are seen in the miner's mempool.
|
|
||||||
var txids []*chainhash.Hash
|
|
||||||
var err error
|
|
||||||
if numTxs > 0 {
|
|
||||||
txids, err = waitForNTxsInMempool(
|
|
||||||
net.Miner.Client, numTxs, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to find txns in mempool: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks := make([]*wire.MsgBlock, num)
|
|
||||||
|
|
||||||
blockHashes, err := net.Miner.Client.Generate(num)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to generate blocks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, blockHash := range blockHashes {
|
|
||||||
block, err := net.Miner.Client.GetBlock(blockHash)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get block: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks[i] = block
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, assert that all the transactions were included in the first
|
|
||||||
// block.
|
|
||||||
for _, txid := range txids {
|
|
||||||
assertTxInBlock(t, blocks[0], txid)
|
|
||||||
}
|
|
||||||
|
|
||||||
return blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
// mineBlocksSlow mines 'num' of blocks and checks that blocks are present in
|
|
||||||
// the mining node's blockchain. numTxs should be set to the number of
|
|
||||||
// transactions (excluding the coinbase) we expect to be included in the first
|
|
||||||
// mined block. Between each mined block an artificial delay is introduced to
|
|
||||||
// give all network participants time to catch up.
|
|
||||||
//
|
|
||||||
// NOTE: This function currently is just an alias for mineBlocksSlow.
|
|
||||||
func mineBlocks(t *harnessTest, net *lntest.NetworkHarness,
|
|
||||||
num uint32, numTxs int) []*wire.MsgBlock {
|
|
||||||
|
|
||||||
return mineBlocksSlow(t, net, num, numTxs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mineBlocksSlow mines 'num' of blocks and checks that blocks are present in
|
|
||||||
// the mining node's blockchain. numTxs should be set to the number of
|
|
||||||
// transactions (excluding the coinbase) we expect to be included in the first
|
|
||||||
// mined block. Between each mined block an artificial delay is introduced to
|
|
||||||
// give all network participants time to catch up.
|
|
||||||
func mineBlocksSlow(t *harnessTest, net *lntest.NetworkHarness,
|
|
||||||
num uint32, numTxs int) []*wire.MsgBlock {
|
|
||||||
|
|
||||||
t.t.Helper()
|
|
||||||
|
|
||||||
// If we expect transactions to be included in the blocks we'll mine,
|
|
||||||
// we wait here until they are seen in the miner's mempool.
|
|
||||||
var txids []*chainhash.Hash
|
|
||||||
var err error
|
|
||||||
if numTxs > 0 {
|
|
||||||
txids, err = waitForNTxsInMempool(
|
|
||||||
net.Miner.Client, numTxs, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err, "unable to find txns in mempool")
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks := make([]*wire.MsgBlock, num)
|
|
||||||
blockHashes := make([]*chainhash.Hash, 0, num)
|
|
||||||
|
|
||||||
for i := uint32(0); i < num; i++ {
|
|
||||||
generatedHashes, err := net.Miner.Client.Generate(1)
|
|
||||||
require.NoError(t.t, err, "generate blocks")
|
|
||||||
blockHashes = append(blockHashes, generatedHashes...)
|
|
||||||
|
|
||||||
time.Sleep(slowMineDelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, blockHash := range blockHashes {
|
|
||||||
block, err := net.Miner.Client.GetBlock(blockHash)
|
|
||||||
require.NoError(t.t, err, "get blocks")
|
|
||||||
|
|
||||||
blocks[i] = block
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, assert that all the transactions were included in the first
|
|
||||||
// block.
|
|
||||||
for _, txid := range txids {
|
|
||||||
assertTxInBlock(t, blocks[0], txid)
|
|
||||||
}
|
|
||||||
|
|
||||||
return blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertTxInBlock(t *harnessTest, block *wire.MsgBlock, txid *chainhash.Hash) {
|
|
||||||
for _, tx := range block.Transactions {
|
|
||||||
sha := tx.TxHash()
|
|
||||||
if bytes.Equal(txid[:], sha[:]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Fatalf("tx was not included in block")
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertWalletUnspent(t *harnessTest, node *lntest.HarnessNode,
|
|
||||||
out *lnrpc.OutPoint, account string) {
|
|
||||||
|
|
||||||
t.t.Helper()
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
err := wait.NoError(func() error {
|
|
||||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
unspent, err := node.WalletKitClient.ListUnspent(
|
|
||||||
ctxt, &walletrpc.ListUnspentRequest{
|
|
||||||
Account: account,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = errors.New("tx with wanted txhash never found")
|
|
||||||
for _, utxo := range unspent.Utxos {
|
|
||||||
if !bytes.Equal(utxo.Outpoint.TxidBytes, out.TxidBytes) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = errors.New("wanted output is not a wallet utxo")
|
|
||||||
if utxo.Outpoint.OutputIndex != out.OutputIndex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}, defaultTimeout)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
}
|
|
||||||
+26
-386
@@ -1,211 +1,42 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"flag"
|
||||||
"crypto/rand"
|
"math"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
"github.com/go-errors/errors"
|
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// completePaymentRequests sends payments from a lightning node to complete all
|
const (
|
||||||
// payment requests. If the awaitResponse parameter is true, this function
|
testFeeBase = 1e+6
|
||||||
// does not return until all payments successfully complete without errors.
|
defaultCSV = node.DefaultCSV
|
||||||
func completePaymentRequests(client lnrpc.LightningClient,
|
defaultTimeout = wait.DefaultTimeout
|
||||||
routerClient routerrpc.RouterClient, paymentRequests []string,
|
itestLndBinary = "../../lnd-itest"
|
||||||
awaitResponse bool) error {
|
anchorSize = 330
|
||||||
|
noFeeLimitMsat = math.MaxInt64
|
||||||
|
|
||||||
ctxb := context.Background()
|
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
|
||||||
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
|
||||||
defer cancel()
|
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
|
||||||
|
)
|
||||||
|
|
||||||
// We start by getting the current state of the client's channels. This
|
var (
|
||||||
// is needed to ensure the payments actually have been committed before
|
harnessNetParams = &chaincfg.RegressionNetParams
|
||||||
// we return.
|
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
|
||||||
listResp, err := client.ListChannels(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// send sends a payment and returns an error if it doesn't succeeded.
|
// lndExecutable is the full path to the lnd binary.
|
||||||
send := func(payReq string) error {
|
lndExecutable = flag.String(
|
||||||
ctxc, cancel := context.WithCancel(ctx)
|
"lndexec", itestLndBinary, "full path to lnd binary",
|
||||||
defer cancel()
|
)
|
||||||
|
)
|
||||||
payStream, err := routerClient.SendPaymentV2(
|
|
||||||
ctxc,
|
|
||||||
&routerrpc.SendPaymentRequest{
|
|
||||||
PaymentRequest: payReq,
|
|
||||||
TimeoutSeconds: 60,
|
|
||||||
FeeLimitMsat: noFeeLimitMsat,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := getPaymentResult(payStream)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if resp.Status != lnrpc.Payment_SUCCEEDED {
|
|
||||||
return errors.New(resp.FailureReason)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch all payments simultaneously.
|
|
||||||
results := make(chan error)
|
|
||||||
for _, payReq := range paymentRequests {
|
|
||||||
go func(payReq string) {
|
|
||||||
err := send(payReq)
|
|
||||||
if awaitResponse {
|
|
||||||
results <- err
|
|
||||||
}
|
|
||||||
}(payReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If awaiting a response, verify that all payments succeeded.
|
|
||||||
if awaitResponse {
|
|
||||||
for range paymentRequests {
|
|
||||||
err := <-results
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are not waiting for feedback in the form of a response, but we
|
|
||||||
// should still wait long enough for the server to receive and handle
|
|
||||||
// the send before cancelling the request. We wait for the number of
|
|
||||||
// updates to one of our channels has increased before we return.
|
|
||||||
err = wait.Predicate(func() bool {
|
|
||||||
newListResp, err := client.ListChannels(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the number of open channels is now lower than before
|
|
||||||
// attempting the payments, it means one of the payments
|
|
||||||
// triggered a force closure (for example, due to an incorrect
|
|
||||||
// preimage). Return early since it's clear the payment was
|
|
||||||
// attempted.
|
|
||||||
if len(newListResp.Channels) < len(listResp.Channels) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c1 := range listResp.Channels {
|
|
||||||
for _, c2 := range newListResp.Channels {
|
|
||||||
if c1.ChannelPoint != c2.ChannelPoint {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this channel has an increased numbr of
|
|
||||||
// updates, we assume the payments are
|
|
||||||
// committed, and we can return.
|
|
||||||
if c2.NumUpdates > c1.NumUpdates {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}, defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeFakePayHash creates random pre image hash.
|
|
||||||
func makeFakePayHash(t *harnessTest) []byte {
|
|
||||||
randBuf := make([]byte, 32)
|
|
||||||
|
|
||||||
if _, err := rand.Read(randBuf); err != nil {
|
|
||||||
t.Fatalf("internal error, cannot generate random string: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return randBuf
|
|
||||||
}
|
|
||||||
|
|
||||||
// createPayReqs is a helper method that will create a slice of payment
|
|
||||||
// requests for the given node.
|
|
||||||
func createPayReqs(node *lntest.HarnessNode, paymentAmt btcutil.Amount,
|
|
||||||
numInvoices int) ([]string, [][]byte, []*lnrpc.Invoice, error) {
|
|
||||||
|
|
||||||
payReqs := make([]string, numInvoices)
|
|
||||||
rHashes := make([][]byte, numInvoices)
|
|
||||||
invoices := make([]*lnrpc.Invoice, numInvoices)
|
|
||||||
for i := 0; i < numInvoices; i++ {
|
|
||||||
preimage := make([]byte, 32)
|
|
||||||
_, err := rand.Read(preimage)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("unable to generate "+
|
|
||||||
"preimage: %v", err)
|
|
||||||
}
|
|
||||||
invoice := &lnrpc.Invoice{
|
|
||||||
Memo: "testing",
|
|
||||||
RPreimage: preimage,
|
|
||||||
Value: int64(paymentAmt),
|
|
||||||
}
|
|
||||||
ctxt, _ := context.WithTimeout(
|
|
||||||
context.Background(), defaultTimeout,
|
|
||||||
)
|
|
||||||
resp, err := node.AddInvoice(ctxt, invoice)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("unable to add "+
|
|
||||||
"invoice: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the payment address in the invoice so the caller can
|
|
||||||
// properly use it.
|
|
||||||
invoice.PaymentAddr = resp.PaymentAddr
|
|
||||||
|
|
||||||
payReqs[i] = resp.PaymentRequest
|
|
||||||
rHashes[i] = resp.RHash
|
|
||||||
invoices[i] = invoice
|
|
||||||
}
|
|
||||||
return payReqs, rHashes, invoices, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getChanInfo is a helper method for getting channel info for a node's sole
|
|
||||||
// channel.
|
|
||||||
func getChanInfo(node *lntest.HarnessNode) (*lnrpc.Channel, error) {
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
|
||||||
channelInfo, err := node.ListChannels(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(channelInfo.Channels) != 1 {
|
|
||||||
return nil, fmt.Errorf("node should only have a single "+
|
|
||||||
"channel, instead it has %v", len(channelInfo.Channels))
|
|
||||||
}
|
|
||||||
|
|
||||||
return channelInfo.Channels[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// commitTypeHasAnchors returns whether commitType uses anchor outputs.
|
// commitTypeHasAnchors returns whether commitType uses anchor outputs.
|
||||||
func commitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
|
func commitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
|
||||||
@@ -247,8 +78,9 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
|
|||||||
feePerKw = chainfee.SatPerKWeight(
|
feePerKw = chainfee.SatPerKWeight(
|
||||||
lntemp.DefaultFeeRateSatPerKw,
|
lntemp.DefaultFeeRateSatPerKw,
|
||||||
)
|
)
|
||||||
commitWeight = input.CommitWeight
|
commitWeight = input.CommitWeight
|
||||||
anchors = btcutil.Amount(0)
|
anchors = btcutil.Amount(0)
|
||||||
|
defaultSatPerVByte = lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
|
||||||
)
|
)
|
||||||
|
|
||||||
// The anchor commitment type is slightly heavier, and we must also add
|
// The anchor commitment type is slightly heavier, and we must also add
|
||||||
@@ -257,8 +89,7 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
|
|||||||
// channels.
|
// channels.
|
||||||
if commitTypeHasAnchors(c) {
|
if commitTypeHasAnchors(c) {
|
||||||
feePerKw = chainfee.SatPerKVByte(
|
feePerKw = chainfee.SatPerKVByte(
|
||||||
lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000,
|
defaultSatPerVByte * 1000).FeePerKWeight()
|
||||||
).FeePerKWeight()
|
|
||||||
commitWeight = input.AnchorCommitWeight
|
commitWeight = input.AnchorCommitWeight
|
||||||
anchors = 2 * anchorSize
|
anchors = 2 * anchorSize
|
||||||
}
|
}
|
||||||
@@ -267,29 +98,6 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
|
|||||||
anchors
|
anchors
|
||||||
}
|
}
|
||||||
|
|
||||||
// channelCommitType retrieves the active channel commitment type for the given
|
|
||||||
// chan point.
|
|
||||||
func channelCommitType(node *lntest.HarnessNode,
|
|
||||||
chanPoint *lnrpc.ChannelPoint) (lnrpc.CommitmentType, error) {
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
|
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
|
||||||
channels, err := node.ListChannels(ctxt, req)
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("listchannels failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range channels.Channels {
|
|
||||||
if c.ChannelPoint == txStr(chanPoint) {
|
|
||||||
return c.CommitmentType, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, fmt.Errorf("channel point %v not found", chanPoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateMaxHtlc re-implements the RequiredRemoteChannelReserve of the
|
// calculateMaxHtlc re-implements the RequiredRemoteChannelReserve of the
|
||||||
// funding manager's config, which corresponds to the maximum MaxHTLC value we
|
// funding manager's config, which corresponds to the maximum MaxHTLC value we
|
||||||
// allow users to set when updating a channel policy.
|
// allow users to set when updating a channel policy.
|
||||||
@@ -298,171 +106,3 @@ func calculateMaxHtlc(chanCap btcutil.Amount) uint64 {
|
|||||||
max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
|
max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
|
||||||
return uint64(max)
|
return uint64(max)
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitForNodeBlockHeight queries the node for its current block height until
|
|
||||||
// it reaches the passed height.
|
|
||||||
func waitForNodeBlockHeight(node *lntest.HarnessNode, height int32) error {
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
var predErr error
|
|
||||||
err := wait.Predicate(func() bool {
|
|
||||||
info, err := node.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
|
||||||
if err != nil {
|
|
||||||
predErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if int32(info.BlockHeight) != height {
|
|
||||||
predErr = fmt.Errorf("expected block height to "+
|
|
||||||
"be %v, was %v", height, info.BlockHeight)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}, defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return predErr
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getNTxsFromMempool polls until finding the desired number of transactions in
|
|
||||||
// the provided miner's mempool and returns the full transactions to the caller.
|
|
||||||
func getNTxsFromMempool(miner *rpcclient.Client, n int,
|
|
||||||
timeout time.Duration) ([]*wire.MsgTx, error) {
|
|
||||||
|
|
||||||
txids, err := waitForNTxsInMempool(miner, n, timeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var txes []*wire.MsgTx
|
|
||||||
for _, txid := range txids {
|
|
||||||
tx, err := miner.GetRawTransaction(txid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
txes = append(txes, tx.MsgTx())
|
|
||||||
}
|
|
||||||
return txes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTxFee retrieves parent transactions and reconstructs the fee paid.
|
|
||||||
func getTxFee(miner *rpcclient.Client, tx *wire.MsgTx) (btcutil.Amount, error) {
|
|
||||||
var balance btcutil.Amount
|
|
||||||
for _, in := range tx.TxIn {
|
|
||||||
parentHash := in.PreviousOutPoint.Hash
|
|
||||||
rawTx, err := miner.GetRawTransaction(&parentHash)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
parent := rawTx.MsgTx()
|
|
||||||
balance += btcutil.Amount(
|
|
||||||
parent.TxOut[in.PreviousOutPoint.Index].Value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, out := range tx.TxOut {
|
|
||||||
balance -= btcutil.Amount(out.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return balance, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// channelSubscription houses the proxied update and error chans for a node's
|
|
||||||
// channel subscriptions.
|
|
||||||
type channelSubscription struct {
|
|
||||||
updateChan chan *lnrpc.ChannelEventUpdate
|
|
||||||
errChan chan error
|
|
||||||
quit chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// subscribeChannelNotifications subscribes to channel updates and launches a
|
|
||||||
// goroutine that forwards these to the returned channel.
|
|
||||||
func subscribeChannelNotifications(ctxb context.Context, t *harnessTest,
|
|
||||||
node *lntest.HarnessNode) channelSubscription {
|
|
||||||
|
|
||||||
// We'll first start by establishing a notification client which will
|
|
||||||
// send us notifications upon channels becoming active, inactive or
|
|
||||||
// closed.
|
|
||||||
req := &lnrpc.ChannelEventSubscription{}
|
|
||||||
ctx, cancelFunc := context.WithCancel(ctxb)
|
|
||||||
|
|
||||||
chanUpdateClient, err := node.SubscribeChannelEvents(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create channel update client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll launch a goroutine that will be responsible for proxying all
|
|
||||||
// notifications recv'd from the client into the channel below.
|
|
||||||
errChan := make(chan error, 1)
|
|
||||||
quit := make(chan struct{})
|
|
||||||
chanUpdates := make(chan *lnrpc.ChannelEventUpdate, 20)
|
|
||||||
go func() {
|
|
||||||
defer cancelFunc()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-quit:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
chanUpdate, err := chanUpdateClient.Recv()
|
|
||||||
select {
|
|
||||||
case <-quit:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == io.EOF {
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
select {
|
|
||||||
case errChan <- err:
|
|
||||||
case <-quit:
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case chanUpdates <- chanUpdate:
|
|
||||||
case <-quit:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return channelSubscription{
|
|
||||||
updateChan: chanUpdates,
|
|
||||||
errChan: errChan,
|
|
||||||
quit: quit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// findTxAtHeight gets all of the transactions that a node's wallet has a record
|
|
||||||
// of at the target height, and finds and returns the tx with the target txid,
|
|
||||||
// failing if it is not found.
|
|
||||||
func findTxAtHeight(t *harnessTest, height int32,
|
|
||||||
target string, node *lntest.HarnessNode) *lnrpc.Transaction {
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
txns, err := node.LightningClient.GetTransactions(
|
|
||||||
ctx, &lnrpc.GetTransactionsRequest{
|
|
||||||
StartHeight: height,
|
|
||||||
EndHeight: height,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err, "could not get transactions")
|
|
||||||
|
|
||||||
for _, tx := range txns.Transactions {
|
|
||||||
if tx.TxHash == target {
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -61,7 +61,7 @@ var _ WebFeeService = (*FeeService)(nil)
|
|||||||
|
|
||||||
// Start spins up a go-routine to serve fee estimates.
|
// Start spins up a go-routine to serve fee estimates.
|
||||||
func NewFeeService(t *testing.T) *FeeService {
|
func NewFeeService(t *testing.T) *FeeService {
|
||||||
port := lntest.NextAvailablePort()
|
port := node.NextAvailablePort()
|
||||||
f := FeeService{
|
f := FeeService{
|
||||||
T: t,
|
T: t,
|
||||||
url: fmt.Sprintf(
|
url: fmt.Sprintf(
|
||||||
|
|||||||
+4
-5
@@ -19,7 +19,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
@@ -100,7 +99,7 @@ type HarnessTest struct {
|
|||||||
// NewHarnessTest creates a new instance of a harnessTest from a regular
|
// NewHarnessTest creates a new instance of a harnessTest from a regular
|
||||||
// testing.T instance.
|
// testing.T instance.
|
||||||
func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
|
func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
|
||||||
dbBackend lntest.DatabaseBackend) *HarnessTest {
|
dbBackend node.DatabaseBackend) *HarnessTest {
|
||||||
|
|
||||||
// Create the run context.
|
// Create the run context.
|
||||||
ctxt, cancel := context.WithCancel(context.Background())
|
ctxt, cancel := context.WithCancel(context.Background())
|
||||||
@@ -636,7 +635,7 @@ func (h *HarnessTest) NewNodeEtcd(name string, etcdCfg *etcd.Config,
|
|||||||
leaderSessionTTL int) *node.HarnessNode {
|
leaderSessionTTL int) *node.HarnessNode {
|
||||||
|
|
||||||
// We don't want to use the embedded etcd instance.
|
// We don't want to use the embedded etcd instance.
|
||||||
h.manager.dbBackend = lntest.BackendBbolt
|
h.manager.dbBackend = node.BackendBbolt
|
||||||
|
|
||||||
extraArgs := node.ExtraArgsEtcd(
|
extraArgs := node.ExtraArgsEtcd(
|
||||||
etcdCfg, name, cluster, leaderSessionTTL,
|
etcdCfg, name, cluster, leaderSessionTTL,
|
||||||
@@ -659,7 +658,7 @@ func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config,
|
|||||||
leaderSessionTTL int) (*node.HarnessNode, []string, []byte) {
|
leaderSessionTTL int) (*node.HarnessNode, []string, []byte) {
|
||||||
|
|
||||||
// We don't want to use the embedded etcd instance.
|
// We don't want to use the embedded etcd instance.
|
||||||
h.manager.dbBackend = lntest.BackendBbolt
|
h.manager.dbBackend = node.BackendBbolt
|
||||||
|
|
||||||
// Create a request to generate a new aezeed. The new seed will have
|
// Create a request to generate a new aezeed. The new seed will have
|
||||||
// the same password as the internal wallet.
|
// the same password as the internal wallet.
|
||||||
@@ -1402,7 +1401,7 @@ func (h *HarnessTest) CleanupForceClose(hn *node.HarnessNode,
|
|||||||
//
|
//
|
||||||
// The commit sweep resolver is able to broadcast the sweep tx up to
|
// The commit sweep resolver is able to broadcast the sweep tx up to
|
||||||
// one block before the CSV elapses, so wait until defaulCSV-1.
|
// one block before the CSV elapses, so wait until defaulCSV-1.
|
||||||
h.MineBlocks(lntest.DefaultCSV - 1)
|
h.MineBlocks(node.DefaultCSV - 1)
|
||||||
|
|
||||||
// The node should now sweep the funds, clean up by mining the sweeping
|
// The node should now sweep the funds, clean up by mining the sweeping
|
||||||
// tx.
|
// tx.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -73,8 +73,8 @@ func newMiner(ctxb context.Context, t *testing.T, minerDirName,
|
|||||||
logFilename string) *HarnessMiner {
|
logFilename string) *HarnessMiner {
|
||||||
|
|
||||||
handler := &rpcclient.NotificationHandlers{}
|
handler := &rpcclient.NotificationHandlers{}
|
||||||
btcdBinary := lntest.GetBtcdBinary()
|
btcdBinary := node.GetBtcdBinary()
|
||||||
baseLogPath := fmt.Sprintf("%s/%s", lntest.GetLogDir(), minerDirName)
|
baseLogPath := fmt.Sprintf("%s/%s", node.GetLogDir(), minerDirName)
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"--rejectnonstd",
|
"--rejectnonstd",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ type nodeManager struct {
|
|||||||
lndBinary string
|
lndBinary string
|
||||||
|
|
||||||
// dbBackend sets the database backend to use.
|
// dbBackend sets the database backend to use.
|
||||||
dbBackend lntest.DatabaseBackend
|
dbBackend node.DatabaseBackend
|
||||||
|
|
||||||
// activeNodes is a map of all running nodes, format:
|
// activeNodes is a map of all running nodes, format:
|
||||||
// {pubkey: *HarnessNode}.
|
// {pubkey: *HarnessNode}.
|
||||||
@@ -50,7 +49,7 @@ type nodeManager struct {
|
|||||||
|
|
||||||
// newNodeManager creates a new node manager instance.
|
// newNodeManager creates a new node manager instance.
|
||||||
func newNodeManager(lndBinary string,
|
func newNodeManager(lndBinary string,
|
||||||
dbBackend lntest.DatabaseBackend) *nodeManager {
|
dbBackend node.DatabaseBackend) *nodeManager {
|
||||||
|
|
||||||
return &nodeManager{
|
return &nodeManager{
|
||||||
lndBinary: lndBinary,
|
lndBinary: lndBinary,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -23,7 +24,7 @@ func SetupHarness(t *testing.T, binaryPath, dbBackendName string,
|
|||||||
t.Log("Setting up HarnessTest...")
|
t.Log("Setting up HarnessTest...")
|
||||||
|
|
||||||
// Parse testing flags that influence our test execution.
|
// Parse testing flags that influence our test execution.
|
||||||
logDir := lntest.GetLogDir()
|
logDir := node.GetLogDir()
|
||||||
require.NoError(t, os.MkdirAll(logDir, 0700), "create log dir failed")
|
require.NoError(t, os.MkdirAll(logDir, 0700), "create log dir failed")
|
||||||
|
|
||||||
// Parse database backend
|
// Parse database backend
|
||||||
@@ -82,7 +83,7 @@ func prepareMiner(ctxt context.Context, t *testing.T) *HarnessMiner {
|
|||||||
|
|
||||||
// prepareChainBackend creates a new chain backend.
|
// prepareChainBackend creates a new chain backend.
|
||||||
func prepareChainBackend(t *testing.T,
|
func prepareChainBackend(t *testing.T,
|
||||||
minerAddr string) (lntest.BackendConfig, func()) {
|
minerAddr string) (node.BackendConfig, func()) {
|
||||||
|
|
||||||
chainBackend, cleanUp, err := lntest.NewBackend(
|
chainBackend, cleanUp, err := lntest.NewBackend(
|
||||||
minerAddr, harnessNetParams,
|
minerAddr, harnessNetParams,
|
||||||
@@ -96,21 +97,21 @@ func prepareChainBackend(t *testing.T,
|
|||||||
|
|
||||||
// prepareDbBackend parses a DatabaseBackend based on the name given.
|
// prepareDbBackend parses a DatabaseBackend based on the name given.
|
||||||
func prepareDbBackend(t *testing.T,
|
func prepareDbBackend(t *testing.T,
|
||||||
dbBackendName string) lntest.DatabaseBackend {
|
dbBackendName string) node.DatabaseBackend {
|
||||||
|
|
||||||
var dbBackend lntest.DatabaseBackend
|
var dbBackend node.DatabaseBackend
|
||||||
switch dbBackendName {
|
switch dbBackendName {
|
||||||
case "bbolt":
|
case "bbolt":
|
||||||
dbBackend = lntest.BackendBbolt
|
dbBackend = node.BackendBbolt
|
||||||
|
|
||||||
case "etcd":
|
case "etcd":
|
||||||
dbBackend = lntest.BackendEtcd
|
dbBackend = node.BackendEtcd
|
||||||
|
|
||||||
case "postgres":
|
case "postgres":
|
||||||
dbBackend = lntest.BackendPostgres
|
dbBackend = node.BackendPostgres
|
||||||
|
|
||||||
case "sqlite":
|
case "sqlite":
|
||||||
dbBackend = lntest.BackendSqlite
|
dbBackend = node.BackendSqlite
|
||||||
|
|
||||||
default:
|
default:
|
||||||
require.Fail(t, "unknown db backend")
|
require.Fail(t, "unknown db backend")
|
||||||
|
|||||||
+141
-13
@@ -1,14 +1,18 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/lightningnetwork/lnd/chanbackup"
|
"github.com/lightningnetwork/lnd/chanbackup"
|
||||||
"github.com/lightningnetwork/lnd/kvdb/etcd"
|
"github.com/lightningnetwork/lnd/kvdb/etcd"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,6 +20,49 @@ const (
|
|||||||
// ListenerFormat is the format string that is used to generate local
|
// ListenerFormat is the format string that is used to generate local
|
||||||
// listener addresses.
|
// listener addresses.
|
||||||
ListenerFormat = "127.0.0.1:%d"
|
ListenerFormat = "127.0.0.1:%d"
|
||||||
|
|
||||||
|
// DefaultCSV is the CSV delay (remotedelay) we will start our test
|
||||||
|
// nodes with.
|
||||||
|
DefaultCSV = 4
|
||||||
|
|
||||||
|
// defaultNodePort is the start of the range for listening ports of
|
||||||
|
// harness nodes. Ports are monotonically increasing starting from this
|
||||||
|
// number and are determined by the results of NextAvailablePort().
|
||||||
|
defaultNodePort = 5555
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// lastPort is the last port determined to be free for use by a new
|
||||||
|
// node. It should be used atomically.
|
||||||
|
lastPort uint32 = defaultNodePort
|
||||||
|
|
||||||
|
// logOutput is a flag that can be set to append the output from the
|
||||||
|
// seed nodes to log files.
|
||||||
|
logOutput = flag.Bool("logoutput", false,
|
||||||
|
"log output from node n to file output-n.log")
|
||||||
|
|
||||||
|
// logSubDir is the default directory where the logs are written to if
|
||||||
|
// logOutput is true.
|
||||||
|
logSubDir = flag.String("logdir", ".", "default dir to write logs to")
|
||||||
|
|
||||||
|
// goroutineDump is a flag that can be set to dump the active
|
||||||
|
// goroutines of test nodes on failure.
|
||||||
|
goroutineDump = flag.Bool("goroutinedump", false,
|
||||||
|
"write goroutine dump from node n to file pprof-n.log")
|
||||||
|
|
||||||
|
// btcdExecutable is the full path to the btcd binary.
|
||||||
|
btcdExecutable = flag.String(
|
||||||
|
"btcdexec", "", "full path to btcd binary",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type DatabaseBackend int
|
||||||
|
|
||||||
|
const (
|
||||||
|
BackendBbolt DatabaseBackend = iota
|
||||||
|
BackendEtcd
|
||||||
|
BackendPostgres
|
||||||
|
BackendSqlite
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option is a function for updating a node's configuration.
|
// Option is a function for updating a node's configuration.
|
||||||
@@ -74,7 +121,7 @@ type BaseNodeConfig struct {
|
|||||||
|
|
||||||
FeeURL string
|
FeeURL string
|
||||||
|
|
||||||
DbBackend lntest.DatabaseBackend
|
DbBackend DatabaseBackend
|
||||||
PostgresDsn string
|
PostgresDsn string
|
||||||
|
|
||||||
// NodeID is a unique ID used to identify the node.
|
// NodeID is a unique ID used to identify the node.
|
||||||
@@ -127,16 +174,16 @@ func (cfg BaseNodeConfig) ChanBackupPath() string {
|
|||||||
// current lightning network test.
|
// current lightning network test.
|
||||||
func (cfg *BaseNodeConfig) GenerateListeningPorts() {
|
func (cfg *BaseNodeConfig) GenerateListeningPorts() {
|
||||||
if cfg.P2PPort == 0 {
|
if cfg.P2PPort == 0 {
|
||||||
cfg.P2PPort = lntest.NextAvailablePort()
|
cfg.P2PPort = NextAvailablePort()
|
||||||
}
|
}
|
||||||
if cfg.RPCPort == 0 {
|
if cfg.RPCPort == 0 {
|
||||||
cfg.RPCPort = lntest.NextAvailablePort()
|
cfg.RPCPort = NextAvailablePort()
|
||||||
}
|
}
|
||||||
if cfg.RESTPort == 0 {
|
if cfg.RESTPort == 0 {
|
||||||
cfg.RESTPort = lntest.NextAvailablePort()
|
cfg.RESTPort = NextAvailablePort()
|
||||||
}
|
}
|
||||||
if cfg.ProfilePort == 0 {
|
if cfg.ProfilePort == 0 {
|
||||||
cfg.ProfilePort = lntest.NextAvailablePort()
|
cfg.ProfilePort = NextAvailablePort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,8 +217,7 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
|
|||||||
"--accept-keysend",
|
"--accept-keysend",
|
||||||
"--keep-failed-payment-attempts",
|
"--keep-failed-payment-attempts",
|
||||||
fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval),
|
fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval),
|
||||||
fmt.Sprintf("--bitcoin.defaultremotedelay=%v",
|
fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV),
|
||||||
lntest.DefaultCSV),
|
|
||||||
fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()),
|
fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()),
|
||||||
fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()),
|
fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()),
|
||||||
fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()),
|
fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()),
|
||||||
@@ -200,19 +246,19 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch cfg.DbBackend {
|
switch cfg.DbBackend {
|
||||||
case lntest.BackendEtcd:
|
case BackendEtcd:
|
||||||
args = append(args, "--db.backend=etcd")
|
args = append(args, "--db.backend=etcd")
|
||||||
args = append(args, "--db.etcd.embedded")
|
args = append(args, "--db.etcd.embedded")
|
||||||
args = append(
|
args = append(
|
||||||
args, fmt.Sprintf(
|
args, fmt.Sprintf(
|
||||||
"--db.etcd.embedded_client_port=%v",
|
"--db.etcd.embedded_client_port=%v",
|
||||||
lntest.NextAvailablePort(),
|
NextAvailablePort(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
args = append(
|
args = append(
|
||||||
args, fmt.Sprintf(
|
args, fmt.Sprintf(
|
||||||
"--db.etcd.embedded_peer_port=%v",
|
"--db.etcd.embedded_peer_port=%v",
|
||||||
lntest.NextAvailablePort(),
|
NextAvailablePort(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
args = append(
|
args = append(
|
||||||
@@ -222,11 +268,11 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
case lntest.BackendPostgres:
|
case BackendPostgres:
|
||||||
args = append(args, "--db.backend=postgres")
|
args = append(args, "--db.backend=postgres")
|
||||||
args = append(args, "--db.postgres.dsn="+cfg.PostgresDsn)
|
args = append(args, "--db.postgres.dsn="+cfg.PostgresDsn)
|
||||||
|
|
||||||
case lntest.BackendSqlite:
|
case BackendSqlite:
|
||||||
args = append(args, "--db.backend=sqlite")
|
args = append(args, "--db.backend=sqlite")
|
||||||
args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v",
|
args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v",
|
||||||
wait.SqliteBusyTimeout))
|
wait.SqliteBusyTimeout))
|
||||||
@@ -273,3 +319,85 @@ func ExtraArgsEtcd(etcdCfg *etcd.Config, name string, cluster bool,
|
|||||||
|
|
||||||
return extraArgs
|
return extraArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NextAvailablePort returns the first port that is available for listening by
|
||||||
|
// a new node. It panics if no port is found and the maximum available TCP port
|
||||||
|
// is reached.
|
||||||
|
func NextAvailablePort() int {
|
||||||
|
port := atomic.AddUint32(&lastPort, 1)
|
||||||
|
for port < 65535 {
|
||||||
|
// If there are no errors while attempting to listen on this
|
||||||
|
// port, close the socket and return it as available. While it
|
||||||
|
// could be the case that some other process picks up this port
|
||||||
|
// between the time the socket is closed and it's reopened in
|
||||||
|
// the harness node, in practice in CI servers this seems much
|
||||||
|
// less likely than simply some other process already being
|
||||||
|
// bound at the start of the tests.
|
||||||
|
addr := fmt.Sprintf(ListenerFormat, port)
|
||||||
|
l, err := net.Listen("tcp4", addr)
|
||||||
|
if err == nil {
|
||||||
|
err := l.Close()
|
||||||
|
if err == nil {
|
||||||
|
return int(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port = atomic.AddUint32(&lastPort, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No ports available? Must be a mistake.
|
||||||
|
panic("no ports available for listening")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogDir returns the passed --logdir flag or the default value if it wasn't
|
||||||
|
// set.
|
||||||
|
func GetLogDir() string {
|
||||||
|
if logSubDir != nil && *logSubDir != "" {
|
||||||
|
return *logSubDir
|
||||||
|
}
|
||||||
|
return "."
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile copies the file src to dest.
|
||||||
|
func CopyFile(dest, src string) error {
|
||||||
|
s, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
d, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.Copy(d, s); err != nil {
|
||||||
|
d.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBtcdBinary returns the full path to the binary of the custom built btcd
|
||||||
|
// executable or an empty string if none is set.
|
||||||
|
func GetBtcdBinary() string {
|
||||||
|
if btcdExecutable != nil {
|
||||||
|
return *btcdExecutable
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateBtcdListenerAddresses is a function that returns two listener
|
||||||
|
// addresses with unique ports and should be used to overwrite rpctest's
|
||||||
|
// default generator which is prone to use colliding ports.
|
||||||
|
func GenerateBtcdListenerAddresses() (string, string) {
|
||||||
|
return fmt.Sprintf(ListenerFormat, NextAvailablePort()),
|
||||||
|
fmt.Sprintf(ListenerFormat, NextAvailablePort())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyPortOffset adds the given offset to the lastPort variable, making it
|
||||||
|
// possible to run the tests in parallel without colliding on the same ports.
|
||||||
|
func ApplyPortOffset(offset uint32) {
|
||||||
|
_ = atomic.AddUint32(&lastPort, offset)
|
||||||
|
}
|
||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -117,7 +116,7 @@ func NewHarnessNode(t *testing.T, cfg *BaseNodeConfig) (*HarnessNode, error) {
|
|||||||
|
|
||||||
// Create temporary database.
|
// Create temporary database.
|
||||||
var dbName string
|
var dbName string
|
||||||
if cfg.DbBackend == lntest.BackendPostgres {
|
if cfg.DbBackend == BackendPostgres {
|
||||||
var err error
|
var err error
|
||||||
dbName, err = createTempPgDb()
|
dbName, err = createTempPgDb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -383,7 +382,7 @@ func (hn *HarnessNode) StartLndCmd(ctxb context.Context) error {
|
|||||||
|
|
||||||
// If the logoutput flag is passed, redirect output from the nodes to
|
// If the logoutput flag is passed, redirect output from the nodes to
|
||||||
// log files.
|
// log files.
|
||||||
if *lntest.LogOutput {
|
if *logOutput {
|
||||||
err := addLogFile(hn)
|
err := addLogFile(hn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -918,10 +917,8 @@ func getFinalizedLogFilePrefix(hn *HarnessNode) string {
|
|||||||
hn.PubKey[:logPubKeyBytes],
|
hn.PubKey[:logPubKeyBytes],
|
||||||
)
|
)
|
||||||
|
|
||||||
return fmt.Sprintf("%s/%d-%s-%s-%s",
|
return fmt.Sprintf("%s/%d-%s-%s-%s", GetLogDir(), hn.Cfg.NodeID,
|
||||||
lntest.GetLogDir(), hn.Cfg.NodeID,
|
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name, pubKeyHex)
|
||||||
hn.Cfg.LogFilenamePrefix,
|
|
||||||
hn.Cfg.Name, pubKeyHex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalizeLogfile makes sure the log file cleanup function is initialized,
|
// finalizeLogfile makes sure the log file cleanup function is initialized,
|
||||||
@@ -935,7 +932,7 @@ func finalizeLogfile(hn *HarnessNode) {
|
|||||||
hn.logFile.Close()
|
hn.logFile.Close()
|
||||||
|
|
||||||
// If logoutput flag is not set, return early.
|
// If logoutput flag is not set, return early.
|
||||||
if !*lntest.LogOutput {
|
if !*logOutput {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -948,7 +945,7 @@ func finalizeLogfile(hn *HarnessNode) {
|
|||||||
// finalizeEtcdLog saves the etcd log files when test ends.
|
// finalizeEtcdLog saves the etcd log files when test ends.
|
||||||
func finalizeEtcdLog(hn *HarnessNode) {
|
func finalizeEtcdLog(hn *HarnessNode) {
|
||||||
// Exit early if this is not etcd backend.
|
// Exit early if this is not etcd backend.
|
||||||
if hn.Cfg.DbBackend != lntest.BackendEtcd {
|
if hn.Cfg.DbBackend != BackendEtcd {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +961,7 @@ func finalizeEtcdLog(hn *HarnessNode) {
|
|||||||
func addLogFile(hn *HarnessNode) error {
|
func addLogFile(hn *HarnessNode) error {
|
||||||
var fileName string
|
var fileName string
|
||||||
|
|
||||||
dir := lntest.GetLogDir()
|
dir := GetLogDir()
|
||||||
fileName = fmt.Sprintf("%s/%d-%s-%s-%s.log", dir, hn.Cfg.NodeID,
|
fileName = fmt.Sprintf("%s/%d-%s-%s-%s.log", dir, hn.Cfg.NodeID,
|
||||||
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name,
|
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name,
|
||||||
hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
|
hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
|
||||||
@@ -1028,7 +1025,7 @@ func copyAll(dstDir, srcDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if err := lntest.CopyFile(dstPath, srcPath); err != nil {
|
} else if err := CopyFile(dstPath, srcPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -10,15 +10,14 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// NeutrinoBackendName is the name of the neutrino backend.
|
// NeutrinoBackendName is the name of the neutrino backend.
|
||||||
NeutrinoBackendName = "neutrino"
|
NeutrinoBackendName = "neutrino"
|
||||||
|
|
||||||
// TODO(yy): delete.
|
DefaultTimeout = wait.DefaultTimeout
|
||||||
DefaultTimeout = lntest.DefaultTimeout
|
|
||||||
|
|
||||||
// noFeeLimitMsat is used to specify we will put no requirements on fee
|
// noFeeLimitMsat is used to specify we will put no requirements on fee
|
||||||
// charged when choosing a route path.
|
// charged when choosing a route path.
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
// logDirPattern is the pattern of the name of the temporary log directory.
|
// logDirPattern is the pattern of the name of the temporary log directory.
|
||||||
@@ -37,7 +38,7 @@ type BitcoindBackendConfig struct {
|
|||||||
|
|
||||||
// A compile time assertion to ensure BitcoindBackendConfig meets the
|
// A compile time assertion to ensure BitcoindBackendConfig meets the
|
||||||
// BackendConfig interface.
|
// BackendConfig interface.
|
||||||
var _ BackendConfig = (*BitcoindBackendConfig)(nil)
|
var _ node.BackendConfig = (*BitcoindBackendConfig)(nil)
|
||||||
|
|
||||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||||
// using this node as a chain backend.
|
// using this node as a chain backend.
|
||||||
@@ -89,7 +90,7 @@ func (b BitcoindBackendConfig) Name() string {
|
|||||||
func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
|
func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
|
||||||
rpcPolling bool) (*BitcoindBackendConfig, func() error, error) {
|
rpcPolling bool) (*BitcoindBackendConfig, func() error, error) {
|
||||||
|
|
||||||
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir())
|
baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
|
||||||
if netParams != &chaincfg.RegressionNetParams {
|
if netParams != &chaincfg.RegressionNetParams {
|
||||||
return nil, nil, fmt.Errorf("only regtest supported")
|
return nil, nil, fmt.Errorf("only regtest supported")
|
||||||
}
|
}
|
||||||
@@ -109,10 +110,12 @@ func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
|
|||||||
fmt.Errorf("unable to create temp directory: %v", err)
|
fmt.Errorf("unable to create temp directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort())
|
zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
|
||||||
zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort())
|
node.NextAvailablePort())
|
||||||
rpcPort := NextAvailablePort()
|
zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
|
||||||
p2pPort := NextAvailablePort()
|
node.NextAvailablePort())
|
||||||
|
rpcPort := node.NextAvailablePort()
|
||||||
|
p2pPort := node.NextAvailablePort()
|
||||||
|
|
||||||
cmdArgs := []string{
|
cmdArgs := []string{
|
||||||
"-datadir=" + tempBitcoindDir,
|
"-datadir=" + tempBitcoindDir,
|
||||||
@@ -146,9 +149,9 @@ func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
|
|||||||
// After shutting down the chain backend, we'll make a copy of
|
// After shutting down the chain backend, we'll make a copy of
|
||||||
// the log file before deleting the temporary log dir.
|
// the log file before deleting the temporary log dir.
|
||||||
logDestination := fmt.Sprintf(
|
logDestination := fmt.Sprintf(
|
||||||
"%s/output_bitcoind_chainbackend.log", GetLogDir(),
|
"%s/output_bitcoind_chainbackend.log", node.GetLogDir(),
|
||||||
)
|
)
|
||||||
err := CopyFile(logDestination, logFile)
|
err := node.CopyFile(logDestination, logFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr += fmt.Sprintf("unable to copy file: %v\n", err)
|
errStr += fmt.Sprintf("unable to copy file: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-9
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
// logDirPattern is the pattern of the name of the temporary log directory.
|
// logDirPattern is the pattern of the name of the temporary log directory.
|
||||||
@@ -41,7 +42,7 @@ type BtcdBackendConfig struct {
|
|||||||
|
|
||||||
// A compile time assertion to ensure BtcdBackendConfig meets the BackendConfig
|
// A compile time assertion to ensure BtcdBackendConfig meets the BackendConfig
|
||||||
// interface.
|
// interface.
|
||||||
var _ BackendConfig = (*BtcdBackendConfig)(nil)
|
var _ node.BackendConfig = (*BtcdBackendConfig)(nil)
|
||||||
|
|
||||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||||
// using this node as a chain backend.
|
// using this node as a chain backend.
|
||||||
@@ -83,7 +84,7 @@ func (b BtcdBackendConfig) Name() string {
|
|||||||
func NewBackend(miner string, netParams *chaincfg.Params) (
|
func NewBackend(miner string, netParams *chaincfg.Params) (
|
||||||
*BtcdBackendConfig, func() error, error) {
|
*BtcdBackendConfig, func() error, error) {
|
||||||
|
|
||||||
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir())
|
baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
|
||||||
args := []string{
|
args := []string{
|
||||||
"--rejectnonstd",
|
"--rejectnonstd",
|
||||||
"--txindex",
|
"--txindex",
|
||||||
@@ -98,9 +99,12 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
|||||||
// Don't disconnect if a reply takes too long.
|
// Don't disconnect if a reply takes too long.
|
||||||
"--nostalldetect",
|
"--nostalldetect",
|
||||||
}
|
}
|
||||||
chainBackend, err := rpctest.New(netParams, nil, args, GetBtcdBinary())
|
chainBackend, err := rpctest.New(
|
||||||
|
netParams, nil, args, node.GetBtcdBinary(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to create btcd node: %v", err)
|
return nil, nil, fmt.Errorf("unable to create btcd node: %v",
|
||||||
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to overwrite some of the connection settings to make the
|
// We want to overwrite some of the connection settings to make the
|
||||||
@@ -112,7 +116,8 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
|||||||
chainBackend.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
|
chainBackend.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
|
||||||
|
|
||||||
if err := chainBackend.SetUp(false, 0); err != nil {
|
if err := chainBackend.SetUp(false, 0); err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to set up btcd backend: %v", err)
|
return nil, nil, fmt.Errorf("unable to set up btcd backend: %v",
|
||||||
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bd := &BtcdBackendConfig{
|
bd := &BtcdBackendConfig{
|
||||||
@@ -141,14 +146,16 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
|||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
logFile := fmt.Sprintf("%s/%s", logDir, file.Name())
|
logFile := fmt.Sprintf("%s/%s", logDir, file.Name())
|
||||||
newFilename := strings.Replace(
|
newFilename := strings.Replace(
|
||||||
file.Name(), "btcd.log", "output_btcd_chainbackend.log", 1,
|
file.Name(), "btcd.log",
|
||||||
|
"output_btcd_chainbackend.log", 1,
|
||||||
)
|
)
|
||||||
logDestination := fmt.Sprintf(
|
logDestination := fmt.Sprintf(
|
||||||
"%s/%s", GetLogDir(), newFilename,
|
"%s/%s", node.GetLogDir(), newFilename,
|
||||||
)
|
)
|
||||||
err := CopyFile(logDestination, logFile)
|
err := node.CopyFile(logDestination, logFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr += fmt.Sprintf("unable to copy file: %v\n", err)
|
errStr += fmt.Sprintf("unable to copy file: "+
|
||||||
|
"%v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
package lntest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// feeServiceTarget is the confirmation target for which a fee estimate
|
|
||||||
// is returned. Requests for higher confirmation targets will fall back
|
|
||||||
// to this.
|
|
||||||
feeServiceTarget = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// feeService runs a web service that provides fee estimation information.
|
|
||||||
type feeService struct {
|
|
||||||
feeEstimates
|
|
||||||
|
|
||||||
t *testing.T
|
|
||||||
|
|
||||||
srv *http.Server
|
|
||||||
wg sync.WaitGroup
|
|
||||||
|
|
||||||
url string
|
|
||||||
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// feeEstimates contains the current fee estimates.
|
|
||||||
type feeEstimates struct {
|
|
||||||
Fees map[uint32]uint32 `json:"fee_by_block_target"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// startFeeService spins up a go-routine to serve fee estimates.
|
|
||||||
func startFeeService(t *testing.T) *feeService {
|
|
||||||
port := NextAvailablePort()
|
|
||||||
f := feeService{
|
|
||||||
t: t,
|
|
||||||
url: fmt.Sprintf("http://localhost:%v/fee-estimates.json", port),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize default fee estimate.
|
|
||||||
f.Fees = map[uint32]uint32{feeServiceTarget: 50000}
|
|
||||||
|
|
||||||
listenAddr := fmt.Sprintf(":%v", port)
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("/fee-estimates.json", f.handleRequest)
|
|
||||||
|
|
||||||
f.srv = &http.Server{
|
|
||||||
Addr: listenAddr,
|
|
||||||
Handler: mux,
|
|
||||||
}
|
|
||||||
|
|
||||||
f.wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer f.wg.Done()
|
|
||||||
|
|
||||||
if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
|
|
||||||
f.t.Errorf("error: cannot start fee api: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &f
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleRequest handles a client request for fee estimates.
|
|
||||||
func (f *feeService) handleRequest(w http.ResponseWriter, r *http.Request) {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(f.feeEstimates)
|
|
||||||
if err != nil {
|
|
||||||
f.t.Errorf("error: cannot serialize estimates: %v", err)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.WriteString(w, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
f.t.Errorf("error: cannot send estimates: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop stops the web server.
|
|
||||||
func (f *feeService) stop() {
|
|
||||||
if err := f.srv.Shutdown(context.Background()); err != nil {
|
|
||||||
f.t.Errorf("error: cannot stop fee api: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// setFee changes the current fee estimate for the fixed confirmation target.
|
|
||||||
func (f *feeService) setFee(fee chainfee.SatPerKWeight) {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
f.Fees[feeServiceTarget] = uint32(fee.FeePerKVByte())
|
|
||||||
}
|
|
||||||
|
|
||||||
// setFeeWithConf sets a fee for the given confirmation target.
|
|
||||||
func (f *feeService) setFeeWithConf(fee chainfee.SatPerKWeight, conf uint32) {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
f.Fees[conf] = uint32(fee.FeePerKVByte())
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package lntest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestFeeService tests the itest fee estimating web service.
|
|
||||||
func TestFeeService(t *testing.T) {
|
|
||||||
service := startFeeService(t)
|
|
||||||
defer service.stop()
|
|
||||||
|
|
||||||
service.setFee(5000)
|
|
||||||
|
|
||||||
// Wait for service to start accepting connections.
|
|
||||||
var resp *http.Response
|
|
||||||
require.Eventually(
|
|
||||||
t,
|
|
||||||
func() bool {
|
|
||||||
var err error
|
|
||||||
resp, err = http.Get(service.url) // nolint:bodyclose
|
|
||||||
return err == nil
|
|
||||||
},
|
|
||||||
10*time.Second, time.Second,
|
|
||||||
)
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(
|
|
||||||
t, "{\"fee_by_block_target\":{\"1\":20000}}", string(body),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
package lntest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// minerLogFilename is the default log filename for the miner node.
|
|
||||||
minerLogFilename = "output_btcd_miner.log"
|
|
||||||
|
|
||||||
// minerLogDir is the default log dir for the miner node.
|
|
||||||
minerLogDir = ".minerlogs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var harnessNetParams = &chaincfg.RegressionNetParams
|
|
||||||
|
|
||||||
type HarnessMiner struct {
|
|
||||||
*rpctest.Harness
|
|
||||||
|
|
||||||
// runCtx is a context with cancel method. It's used to signal when the
|
|
||||||
// node needs to quit, and used as the parent context when spawning
|
|
||||||
runCtx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
|
|
||||||
// logPath is the directory path of the miner's logs.
|
|
||||||
logPath string
|
|
||||||
|
|
||||||
// logFilename is the saved log filename of the miner node.
|
|
||||||
logFilename string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMiner creates a new miner using btcd backend with the default log file
|
|
||||||
// dir and name.
|
|
||||||
func NewMiner() (*HarnessMiner, error) {
|
|
||||||
return newMiner(minerLogDir, minerLogFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTempMiner creates a new miner using btcd backend with the specified log
|
|
||||||
// file dir and name.
|
|
||||||
func NewTempMiner(tempDir, tempLogFilename string) (*HarnessMiner, error) {
|
|
||||||
return newMiner(tempDir, tempLogFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMiner creates a new miner using btcd's rpctest.
|
|
||||||
func newMiner(minerDirName, logFilename string) (*HarnessMiner, error) {
|
|
||||||
handler := &rpcclient.NotificationHandlers{}
|
|
||||||
btcdBinary := GetBtcdBinary()
|
|
||||||
baseLogPath := fmt.Sprintf("%s/%s", GetLogDir(), minerDirName)
|
|
||||||
|
|
||||||
args := []string{
|
|
||||||
"--rejectnonstd",
|
|
||||||
"--txindex",
|
|
||||||
"--nowinservice",
|
|
||||||
"--nobanning",
|
|
||||||
"--debuglevel=debug",
|
|
||||||
"--logdir=" + baseLogPath,
|
|
||||||
"--trickleinterval=100ms",
|
|
||||||
// Don't disconnect if a reply takes too long.
|
|
||||||
"--nostalldetect",
|
|
||||||
}
|
|
||||||
|
|
||||||
miner, err := rpctest.New(harnessNetParams, handler, args, btcdBinary)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to create mining node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, cancel := context.WithCancel(context.Background())
|
|
||||||
m := &HarnessMiner{
|
|
||||||
Harness: miner,
|
|
||||||
runCtx: ctxt,
|
|
||||||
cancel: cancel,
|
|
||||||
logPath: baseLogPath,
|
|
||||||
logFilename: logFilename,
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop shuts down the miner and saves its logs.
|
|
||||||
func (h *HarnessMiner) Stop() error {
|
|
||||||
h.cancel()
|
|
||||||
|
|
||||||
if err := h.TearDown(); err != nil {
|
|
||||||
return fmt.Errorf("tear down miner got error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.saveLogs()
|
|
||||||
}
|
|
||||||
|
|
||||||
// saveLogs copies the node logs and save it to the file specified by
|
|
||||||
// h.logFilename.
|
|
||||||
func (h *HarnessMiner) saveLogs() error {
|
|
||||||
// After shutting down the miner, we'll make a copy of the log files
|
|
||||||
// before deleting the temporary log dir.
|
|
||||||
path := fmt.Sprintf("%s/%s", h.logPath, harnessNetParams.Name)
|
|
||||||
files, err := ioutil.ReadDir(path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to read log directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
newFilename := strings.Replace(
|
|
||||||
file.Name(), "btcd.log", h.logFilename, 1,
|
|
||||||
)
|
|
||||||
copyPath := fmt.Sprintf("%s/../%s", h.logPath, newFilename)
|
|
||||||
|
|
||||||
logFile := fmt.Sprintf("%s/%s", path, file.Name())
|
|
||||||
err := CopyFile(filepath.Clean(copyPath), logFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to copy file: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.RemoveAll(h.logPath); err != nil {
|
|
||||||
return fmt.Errorf("cannot remove dir %s: %v", h.logPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForTxInMempool blocks until the target txid is seen in the mempool. If
|
|
||||||
// the transaction isn't seen within the network before the passed timeout,
|
|
||||||
// then an error is returned.
|
|
||||||
func (h *HarnessMiner) waitForTxInMempool(txid chainhash.Hash) error {
|
|
||||||
ticker := time.NewTicker(50 * time.Millisecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
var mempool []*chainhash.Hash
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-h.runCtx.Done():
|
|
||||||
return fmt.Errorf("NetworkHarness has been torn down")
|
|
||||||
case <-time.After(DefaultTimeout):
|
|
||||||
return fmt.Errorf("wanted %v, found %v txs "+
|
|
||||||
"in mempool: %v", txid, len(mempool), mempool)
|
|
||||||
|
|
||||||
case <-ticker.C:
|
|
||||||
var err error
|
|
||||||
mempool, err = h.Client.GetRawMempool()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mempoolTx := range mempool {
|
|
||||||
if *mempoolTx == txid {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NeutrinoBackendConfig is an implementation of the BackendConfig interface
|
// NeutrinoBackendConfig is an implementation of the BackendConfig interface
|
||||||
@@ -17,7 +18,7 @@ type NeutrinoBackendConfig struct {
|
|||||||
|
|
||||||
// A compile time assertion to ensure NeutrinoBackendConfig meets the
|
// A compile time assertion to ensure NeutrinoBackendConfig meets the
|
||||||
// BackendConfig interface.
|
// BackendConfig interface.
|
||||||
var _ BackendConfig = (*NeutrinoBackendConfig)(nil)
|
var _ node.BackendConfig = (*NeutrinoBackendConfig)(nil)
|
||||||
|
|
||||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||||
// using this node as a chain backend.
|
// using this node as a chain backend.
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
package lntest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// defaultNodePort is the start of the range for listening ports of
|
|
||||||
// harness nodes. Ports are monotonically increasing starting from this
|
|
||||||
// number and are determined by the results of nextAvailablePort().
|
|
||||||
defaultNodePort = 5555
|
|
||||||
|
|
||||||
// ListenerFormat is the format string that is used to generate local
|
|
||||||
// listener addresses.
|
|
||||||
ListenerFormat = "127.0.0.1:%d"
|
|
||||||
|
|
||||||
// NeutrinoBackendName is the name of the neutrino backend.
|
|
||||||
NeutrinoBackendName = "neutrino"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DatabaseBackend int
|
|
||||||
|
|
||||||
const (
|
|
||||||
BackendBbolt DatabaseBackend = iota
|
|
||||||
BackendEtcd
|
|
||||||
BackendPostgres
|
|
||||||
BackendSqlite
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// lastPort is the last port determined to be free for use by a new
|
|
||||||
// node. It should be used atomically.
|
|
||||||
lastPort uint32 = defaultNodePort
|
|
||||||
|
|
||||||
// logOutput is a flag that can be set to append the output from the
|
|
||||||
// seed nodes to log files.
|
|
||||||
//
|
|
||||||
// TODO(yy): remove the export.
|
|
||||||
LogOutput = flag.Bool("logoutput", false,
|
|
||||||
"log output from node n to file output-n.log")
|
|
||||||
|
|
||||||
// logSubDir is the default directory where the logs are written to if
|
|
||||||
// logOutput is true.
|
|
||||||
logSubDir = flag.String("logdir", ".", "default dir to write logs to")
|
|
||||||
|
|
||||||
// goroutineDump is a flag that can be set to dump the active
|
|
||||||
// goroutines of test nodes on failure.
|
|
||||||
goroutineDump = flag.Bool("goroutinedump", false,
|
|
||||||
"write goroutine dump from node n to file pprof-n.log")
|
|
||||||
|
|
||||||
// btcdExecutable is the full path to the btcd binary.
|
|
||||||
btcdExecutable = flag.String(
|
|
||||||
"btcdexec", "", "full path to btcd binary",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// NextAvailablePort returns the first port that is available for listening by
|
|
||||||
// a new node. It panics if no port is found and the maximum available TCP port
|
|
||||||
// is reached.
|
|
||||||
func NextAvailablePort() int {
|
|
||||||
port := atomic.AddUint32(&lastPort, 1)
|
|
||||||
for port < 65535 {
|
|
||||||
// If there are no errors while attempting to listen on this
|
|
||||||
// port, close the socket and return it as available. While it
|
|
||||||
// could be the case that some other process picks up this port
|
|
||||||
// between the time the socket is closed and it's reopened in
|
|
||||||
// the harness node, in practice in CI servers this seems much
|
|
||||||
// less likely than simply some other process already being
|
|
||||||
// bound at the start of the tests.
|
|
||||||
addr := fmt.Sprintf(ListenerFormat, port)
|
|
||||||
l, err := net.Listen("tcp4", addr)
|
|
||||||
if err == nil {
|
|
||||||
err := l.Close()
|
|
||||||
if err == nil {
|
|
||||||
return int(port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
port = atomic.AddUint32(&lastPort, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// No ports available? Must be a mistake.
|
|
||||||
panic("no ports available for listening")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyPortOffset adds the given offset to the lastPort variable, making it
|
|
||||||
// possible to run the tests in parallel without colliding on the same ports.
|
|
||||||
func ApplyPortOffset(offset uint32) {
|
|
||||||
_ = atomic.AddUint32(&lastPort, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogDir returns the passed --logdir flag or the default value if it wasn't
|
|
||||||
// set.
|
|
||||||
func GetLogDir() string {
|
|
||||||
if logSubDir != nil && *logSubDir != "" {
|
|
||||||
return *logSubDir
|
|
||||||
}
|
|
||||||
return "."
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBtcdBinary returns the full path to the binary of the custom built btcd
|
|
||||||
// executable or an empty string if none is set.
|
|
||||||
func GetBtcdBinary() string {
|
|
||||||
if btcdExecutable != nil {
|
|
||||||
return *btcdExecutable
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateBtcdListenerAddresses is a function that returns two listener
|
|
||||||
// addresses with unique ports and should be used to overwrite rpctest's
|
|
||||||
// default generator which is prone to use colliding ports.
|
|
||||||
func GenerateBtcdListenerAddresses() (string, string) {
|
|
||||||
return fmt.Sprintf(ListenerFormat, NextAvailablePort()),
|
|
||||||
fmt.Sprintf(ListenerFormat, NextAvailablePort())
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeOutpoint returns the outpoint of the channel's funding transaction.
|
|
||||||
func MakeOutpoint(chanPoint *lnrpc.ChannelPoint) (wire.OutPoint, error) {
|
|
||||||
fundingTxID, err := lnrpc.GetChanPointFundingTxid(chanPoint)
|
|
||||||
if err != nil {
|
|
||||||
return wire.OutPoint{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return wire.OutPoint{
|
|
||||||
Hash: *fundingTxID,
|
|
||||||
Index: chanPoint.OutputIndex,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckChannelPolicy checks that the policy matches the expected one.
|
|
||||||
func CheckChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error {
|
|
||||||
if policy.FeeBaseMsat != expectedPolicy.FeeBaseMsat {
|
|
||||||
return fmt.Errorf("expected base fee %v, got %v",
|
|
||||||
expectedPolicy.FeeBaseMsat, policy.FeeBaseMsat)
|
|
||||||
}
|
|
||||||
if policy.FeeRateMilliMsat != expectedPolicy.FeeRateMilliMsat {
|
|
||||||
return fmt.Errorf("expected fee rate %v, got %v",
|
|
||||||
expectedPolicy.FeeRateMilliMsat,
|
|
||||||
policy.FeeRateMilliMsat)
|
|
||||||
}
|
|
||||||
if policy.TimeLockDelta != expectedPolicy.TimeLockDelta {
|
|
||||||
return fmt.Errorf("expected time lock delta %v, got %v",
|
|
||||||
expectedPolicy.TimeLockDelta,
|
|
||||||
policy.TimeLockDelta)
|
|
||||||
}
|
|
||||||
if policy.MinHtlc != expectedPolicy.MinHtlc {
|
|
||||||
return fmt.Errorf("expected min htlc %v, got %v",
|
|
||||||
expectedPolicy.MinHtlc, policy.MinHtlc)
|
|
||||||
}
|
|
||||||
if policy.MaxHtlcMsat != expectedPolicy.MaxHtlcMsat {
|
|
||||||
return fmt.Errorf("expected max htlc %v, got %v",
|
|
||||||
expectedPolicy.MaxHtlcMsat, policy.MaxHtlcMsat)
|
|
||||||
}
|
|
||||||
if policy.Disabled != expectedPolicy.Disabled {
|
|
||||||
return errors.New("edge should be disabled but isn't")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyFile copies the file src to dest.
|
|
||||||
func CopyFile(dest, src string) error {
|
|
||||||
s, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
d, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.Copy(d, s); err != nil {
|
|
||||||
d.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.Close()
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user