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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"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
|
||||
// gets propagated to other nodes in the network.
|
||||
func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -56,8 +56,8 @@ func testEtcdFailover(ht *lntemp.HarnessTest) {
|
||||
|
||||
func testEtcdFailoverCase(ht *lntemp.HarnessTest, kill bool) {
|
||||
etcdCfg, cleanup, err := kvdb.StartEtcdTestBackend(
|
||||
ht.T.TempDir(), uint16(lntest.NextAvailablePort()),
|
||||
uint16(lntest.NextAvailablePort()), "",
|
||||
ht.T.TempDir(), uint16(node.NextAvailablePort()),
|
||||
uint16(node.NextAvailablePort()), "",
|
||||
)
|
||||
require.NoError(ht, err, "Failed to start etcd instance")
|
||||
defer cleanup()
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/routing"
|
||||
"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.
|
||||
type caseRunner func(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode,
|
||||
c lnrpc.CommitmentType, zeroConf bool)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"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
|
||||
// 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.
|
||||
daveArgs := []string{fmt.Sprintf("--externalip=127.0.0.1:%d", ip2)}
|
||||
@@ -184,7 +183,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
|
||||
// address.
|
||||
|
||||
// Change Dave's listening port and restart.
|
||||
dave.Cfg.P2PPort = lntest.NextAvailablePort()
|
||||
dave.Cfg.P2PPort = node.NextAvailablePort()
|
||||
dave.Cfg.ExtraArgs = []string{
|
||||
fmt.Sprintf(
|
||||
"--externalip=127.0.0.1:%d", dave.Cfg.P2PPort,
|
||||
|
||||
@@ -3,14 +3,13 @@ package itest
|
||||
import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testNeutrino checks that the neutrino sub-server can fetch compact
|
||||
// block filters, server status and connect to a connected peer.
|
||||
func testNeutrino(ht *lntemp.HarnessTest) {
|
||||
if ht.ChainBackendName() != lntest.NeutrinoBackendName {
|
||||
if !ht.IsNeutrinoBackend() {
|
||||
ht.Skipf("skipping test for non neutrino backends")
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -1187,60 +1186,6 @@ func deriveInternalKey(ht *lntemp.HarnessTest,
|
||||
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
|
||||
// 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.
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"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
|
||||
// included the justice tx we only need to mine extra DefaultCSV-2
|
||||
// blocks to unlock it.
|
||||
ht.MineBlocks(lntest.DefaultCSV - 2)
|
||||
ht.MineBlocks(defaultCSV - 2)
|
||||
|
||||
ht.AssertNumPendingForceClose(bob, 0)
|
||||
}
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/integration/rpctest"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
@@ -62,7 +62,7 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
||||
|
||||
// Get the test cases to be run in this tranche.
|
||||
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
|
||||
lntest.ApplyPortOffset(uint32(trancheIndex) * 1000)
|
||||
node.ApplyPortOffset(uint32(trancheIndex) * 1000)
|
||||
|
||||
// Create a simple fee service.
|
||||
feeService := lntemp.NewFeeService(t)
|
||||
@@ -188,7 +188,7 @@ func init() {
|
||||
// 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
|
||||
// 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
|
||||
// statements on the floor.
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"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
|
||||
// in the function DisconnectBlockAtHeight.
|
||||
func testZeroConfReorg(ht *lntemp.HarnessTest) {
|
||||
if ht.ChainBackendName() == lntest.NeutrinoBackendName {
|
||||
if ht.IsNeutrinoBackend() {
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
"flag"
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"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/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// completePaymentRequests sends payments from a lightning node to complete all
|
||||
// payment requests. If the awaitResponse parameter is true, this function
|
||||
// does not return until all payments successfully complete without errors.
|
||||
func completePaymentRequests(client lnrpc.LightningClient,
|
||||
routerClient routerrpc.RouterClient, paymentRequests []string,
|
||||
awaitResponse bool) error {
|
||||
const (
|
||||
testFeeBase = 1e+6
|
||||
defaultCSV = node.DefaultCSV
|
||||
defaultTimeout = wait.DefaultTimeout
|
||||
itestLndBinary = "../../lnd-itest"
|
||||
anchorSize = 330
|
||||
noFeeLimitMsat = math.MaxInt64
|
||||
|
||||
ctxb := context.Background()
|
||||
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
|
||||
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
|
||||
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
|
||||
)
|
||||
|
||||
// We start by getting the current state of the client's channels. This
|
||||
// is needed to ensure the payments actually have been committed before
|
||||
// we return.
|
||||
req := &lnrpc.ListChannelsRequest{}
|
||||
listResp, err := client.ListChannels(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
harnessNetParams = &chaincfg.RegressionNetParams
|
||||
|
||||
// send sends a payment and returns an error if it doesn't succeeded.
|
||||
send := func(payReq string) error {
|
||||
ctxc, cancel := context.WithCancel(ctx)
|
||||
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
|
||||
}
|
||||
// lndExecutable is the full path to the lnd binary.
|
||||
lndExecutable = flag.String(
|
||||
"lndexec", itestLndBinary, "full path to lnd binary",
|
||||
)
|
||||
)
|
||||
|
||||
// commitTypeHasAnchors returns whether commitType uses anchor outputs.
|
||||
func commitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
|
||||
@@ -247,8 +78,9 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
|
||||
feePerKw = chainfee.SatPerKWeight(
|
||||
lntemp.DefaultFeeRateSatPerKw,
|
||||
)
|
||||
commitWeight = input.CommitWeight
|
||||
anchors = btcutil.Amount(0)
|
||||
commitWeight = input.CommitWeight
|
||||
anchors = btcutil.Amount(0)
|
||||
defaultSatPerVByte = lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
|
||||
)
|
||||
|
||||
// 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.
|
||||
if commitTypeHasAnchors(c) {
|
||||
feePerKw = chainfee.SatPerKVByte(
|
||||
lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000,
|
||||
).FeePerKWeight()
|
||||
defaultSatPerVByte * 1000).FeePerKWeight()
|
||||
commitWeight = input.AnchorCommitWeight
|
||||
anchors = 2 * anchorSize
|
||||
}
|
||||
@@ -267,29 +98,6 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
|
||||
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
|
||||
// funding manager's config, which corresponds to the maximum MaxHTLC value we
|
||||
// allow users to set when updating a channel policy.
|
||||
@@ -298,171 +106,3 @@ func calculateMaxHtlc(chanCap btcutil.Amount) uint64 {
|
||||
max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
|
||||
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"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -61,7 +61,7 @@ var _ WebFeeService = (*FeeService)(nil)
|
||||
|
||||
// Start spins up a go-routine to serve fee estimates.
|
||||
func NewFeeService(t *testing.T) *FeeService {
|
||||
port := lntest.NextAvailablePort()
|
||||
port := node.NextAvailablePort()
|
||||
f := FeeService{
|
||||
T: t,
|
||||
url: fmt.Sprintf(
|
||||
|
||||
+4
-5
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@@ -100,7 +99,7 @@ type HarnessTest struct {
|
||||
// NewHarnessTest creates a new instance of a harnessTest from a regular
|
||||
// testing.T instance.
|
||||
func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
|
||||
dbBackend lntest.DatabaseBackend) *HarnessTest {
|
||||
dbBackend node.DatabaseBackend) *HarnessTest {
|
||||
|
||||
// Create the run context.
|
||||
ctxt, cancel := context.WithCancel(context.Background())
|
||||
@@ -636,7 +635,7 @@ func (h *HarnessTest) NewNodeEtcd(name string, etcdCfg *etcd.Config,
|
||||
leaderSessionTTL int) *node.HarnessNode {
|
||||
|
||||
// We don't want to use the embedded etcd instance.
|
||||
h.manager.dbBackend = lntest.BackendBbolt
|
||||
h.manager.dbBackend = node.BackendBbolt
|
||||
|
||||
extraArgs := node.ExtraArgsEtcd(
|
||||
etcdCfg, name, cluster, leaderSessionTTL,
|
||||
@@ -659,7 +658,7 @@ func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config,
|
||||
leaderSessionTTL int) (*node.HarnessNode, []string, []byte) {
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// tx.
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"github.com/btcsuite/btcd/integration/rpctest"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -73,8 +73,8 @@ func newMiner(ctxb context.Context, t *testing.T, minerDirName,
|
||||
logFilename string) *HarnessMiner {
|
||||
|
||||
handler := &rpcclient.NotificationHandlers{}
|
||||
btcdBinary := lntest.GetBtcdBinary()
|
||||
baseLogPath := fmt.Sprintf("%s/%s", lntest.GetLogDir(), minerDirName)
|
||||
btcdBinary := node.GetBtcdBinary()
|
||||
baseLogPath := fmt.Sprintf("%s/%s", node.GetLogDir(), minerDirName)
|
||||
|
||||
args := []string{
|
||||
"--rejectnonstd",
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
)
|
||||
|
||||
@@ -30,7 +29,7 @@ type nodeManager struct {
|
||||
lndBinary string
|
||||
|
||||
// dbBackend sets the database backend to use.
|
||||
dbBackend lntest.DatabaseBackend
|
||||
dbBackend node.DatabaseBackend
|
||||
|
||||
// activeNodes is a map of all running nodes, format:
|
||||
// {pubkey: *HarnessNode}.
|
||||
@@ -50,7 +49,7 @@ type nodeManager struct {
|
||||
|
||||
// newNodeManager creates a new node manager instance.
|
||||
func newNodeManager(lndBinary string,
|
||||
dbBackend lntest.DatabaseBackend) *nodeManager {
|
||||
dbBackend node.DatabaseBackend) *nodeManager {
|
||||
|
||||
return &nodeManager{
|
||||
lndBinary: lndBinary,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/integration/rpctest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ func SetupHarness(t *testing.T, binaryPath, dbBackendName string,
|
||||
t.Log("Setting up HarnessTest...")
|
||||
|
||||
// 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")
|
||||
|
||||
// Parse database backend
|
||||
@@ -82,7 +83,7 @@ func prepareMiner(ctxt context.Context, t *testing.T) *HarnessMiner {
|
||||
|
||||
// prepareChainBackend creates a new chain backend.
|
||||
func prepareChainBackend(t *testing.T,
|
||||
minerAddr string) (lntest.BackendConfig, func()) {
|
||||
minerAddr string) (node.BackendConfig, func()) {
|
||||
|
||||
chainBackend, cleanUp, err := lntest.NewBackend(
|
||||
minerAddr, harnessNetParams,
|
||||
@@ -96,21 +97,21 @@ func prepareChainBackend(t *testing.T,
|
||||
|
||||
// prepareDbBackend parses a DatabaseBackend based on the name given.
|
||||
func prepareDbBackend(t *testing.T,
|
||||
dbBackendName string) lntest.DatabaseBackend {
|
||||
dbBackendName string) node.DatabaseBackend {
|
||||
|
||||
var dbBackend lntest.DatabaseBackend
|
||||
var dbBackend node.DatabaseBackend
|
||||
switch dbBackendName {
|
||||
case "bbolt":
|
||||
dbBackend = lntest.BackendBbolt
|
||||
dbBackend = node.BackendBbolt
|
||||
|
||||
case "etcd":
|
||||
dbBackend = lntest.BackendEtcd
|
||||
dbBackend = node.BackendEtcd
|
||||
|
||||
case "postgres":
|
||||
dbBackend = lntest.BackendPostgres
|
||||
dbBackend = node.BackendPostgres
|
||||
|
||||
case "sqlite":
|
||||
dbBackend = lntest.BackendSqlite
|
||||
dbBackend = node.BackendSqlite
|
||||
|
||||
default:
|
||||
require.Fail(t, "unknown db backend")
|
||||
|
||||
+141
-13
@@ -1,14 +1,18 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lightningnetwork/lnd/chanbackup"
|
||||
"github.com/lightningnetwork/lnd/kvdb/etcd"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
)
|
||||
|
||||
@@ -16,6 +20,49 @@ const (
|
||||
// ListenerFormat is the format string that is used to generate local
|
||||
// listener addresses.
|
||||
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.
|
||||
@@ -74,7 +121,7 @@ type BaseNodeConfig struct {
|
||||
|
||||
FeeURL string
|
||||
|
||||
DbBackend lntest.DatabaseBackend
|
||||
DbBackend DatabaseBackend
|
||||
PostgresDsn string
|
||||
|
||||
// NodeID is a unique ID used to identify the node.
|
||||
@@ -127,16 +174,16 @@ func (cfg BaseNodeConfig) ChanBackupPath() string {
|
||||
// current lightning network test.
|
||||
func (cfg *BaseNodeConfig) GenerateListeningPorts() {
|
||||
if cfg.P2PPort == 0 {
|
||||
cfg.P2PPort = lntest.NextAvailablePort()
|
||||
cfg.P2PPort = NextAvailablePort()
|
||||
}
|
||||
if cfg.RPCPort == 0 {
|
||||
cfg.RPCPort = lntest.NextAvailablePort()
|
||||
cfg.RPCPort = NextAvailablePort()
|
||||
}
|
||||
if cfg.RESTPort == 0 {
|
||||
cfg.RESTPort = lntest.NextAvailablePort()
|
||||
cfg.RESTPort = NextAvailablePort()
|
||||
}
|
||||
if cfg.ProfilePort == 0 {
|
||||
cfg.ProfilePort = lntest.NextAvailablePort()
|
||||
cfg.ProfilePort = NextAvailablePort()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +217,7 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
|
||||
"--accept-keysend",
|
||||
"--keep-failed-payment-attempts",
|
||||
fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval),
|
||||
fmt.Sprintf("--bitcoin.defaultremotedelay=%v",
|
||||
lntest.DefaultCSV),
|
||||
fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV),
|
||||
fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()),
|
||||
fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()),
|
||||
fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()),
|
||||
@@ -200,19 +246,19 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
|
||||
}
|
||||
|
||||
switch cfg.DbBackend {
|
||||
case lntest.BackendEtcd:
|
||||
case BackendEtcd:
|
||||
args = append(args, "--db.backend=etcd")
|
||||
args = append(args, "--db.etcd.embedded")
|
||||
args = append(
|
||||
args, fmt.Sprintf(
|
||||
"--db.etcd.embedded_client_port=%v",
|
||||
lntest.NextAvailablePort(),
|
||||
NextAvailablePort(),
|
||||
),
|
||||
)
|
||||
args = append(
|
||||
args, fmt.Sprintf(
|
||||
"--db.etcd.embedded_peer_port=%v",
|
||||
lntest.NextAvailablePort(),
|
||||
NextAvailablePort(),
|
||||
),
|
||||
)
|
||||
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.postgres.dsn="+cfg.PostgresDsn)
|
||||
|
||||
case lntest.BackendSqlite:
|
||||
case BackendSqlite:
|
||||
args = append(args, "--db.backend=sqlite")
|
||||
args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v",
|
||||
wait.SqliteBusyTimeout))
|
||||
@@ -273,3 +319,85 @@ func ExtraArgsEtcd(etcdCfg *etcd.Config, name string, cluster bool,
|
||||
|
||||
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/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp/rpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"google.golang.org/grpc"
|
||||
@@ -117,7 +116,7 @@ func NewHarnessNode(t *testing.T, cfg *BaseNodeConfig) (*HarnessNode, error) {
|
||||
|
||||
// Create temporary database.
|
||||
var dbName string
|
||||
if cfg.DbBackend == lntest.BackendPostgres {
|
||||
if cfg.DbBackend == BackendPostgres {
|
||||
var err error
|
||||
dbName, err = createTempPgDb()
|
||||
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
|
||||
// log files.
|
||||
if *lntest.LogOutput {
|
||||
if *logOutput {
|
||||
err := addLogFile(hn)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -918,10 +917,8 @@ func getFinalizedLogFilePrefix(hn *HarnessNode) string {
|
||||
hn.PubKey[:logPubKeyBytes],
|
||||
)
|
||||
|
||||
return fmt.Sprintf("%s/%d-%s-%s-%s",
|
||||
lntest.GetLogDir(), hn.Cfg.NodeID,
|
||||
hn.Cfg.LogFilenamePrefix,
|
||||
hn.Cfg.Name, pubKeyHex)
|
||||
return fmt.Sprintf("%s/%d-%s-%s-%s", GetLogDir(), hn.Cfg.NodeID,
|
||||
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name, pubKeyHex)
|
||||
}
|
||||
|
||||
// finalizeLogfile makes sure the log file cleanup function is initialized,
|
||||
@@ -935,7 +932,7 @@ func finalizeLogfile(hn *HarnessNode) {
|
||||
hn.logFile.Close()
|
||||
|
||||
// If logoutput flag is not set, return early.
|
||||
if !*lntest.LogOutput {
|
||||
if !*logOutput {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -948,7 +945,7 @@ func finalizeLogfile(hn *HarnessNode) {
|
||||
// finalizeEtcdLog saves the etcd log files when test ends.
|
||||
func finalizeEtcdLog(hn *HarnessNode) {
|
||||
// Exit early if this is not etcd backend.
|
||||
if hn.Cfg.DbBackend != lntest.BackendEtcd {
|
||||
if hn.Cfg.DbBackend != BackendEtcd {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -964,7 +961,7 @@ func finalizeEtcdLog(hn *HarnessNode) {
|
||||
func addLogFile(hn *HarnessNode) error {
|
||||
var fileName string
|
||||
|
||||
dir := lntest.GetLogDir()
|
||||
dir := GetLogDir()
|
||||
fileName = fmt.Sprintf("%s/%d-%s-%s-%s.log", dir, hn.Cfg.NodeID,
|
||||
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name,
|
||||
hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
|
||||
@@ -1028,7 +1025,7 @@ func copyAll(dstDir, srcDir string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := lntest.CopyFile(dstPath, srcPath); err != nil {
|
||||
} else if err := CopyFile(dstPath, srcPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -10,15 +10,14 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
)
|
||||
|
||||
const (
|
||||
// NeutrinoBackendName is the name of the neutrino backend.
|
||||
NeutrinoBackendName = "neutrino"
|
||||
|
||||
// TODO(yy): delete.
|
||||
DefaultTimeout = lntest.DefaultTimeout
|
||||
DefaultTimeout = wait.DefaultTimeout
|
||||
|
||||
// noFeeLimitMsat is used to specify we will put no requirements on fee
|
||||
// charged when choosing a route path.
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
)
|
||||
|
||||
// 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
|
||||
// BackendConfig interface.
|
||||
var _ BackendConfig = (*BitcoindBackendConfig)(nil)
|
||||
var _ node.BackendConfig = (*BitcoindBackendConfig)(nil)
|
||||
|
||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||
// 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,
|
||||
rpcPolling bool) (*BitcoindBackendConfig, func() error, error) {
|
||||
|
||||
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir())
|
||||
baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
|
||||
if netParams != &chaincfg.RegressionNetParams {
|
||||
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)
|
||||
}
|
||||
|
||||
zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort())
|
||||
zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort())
|
||||
rpcPort := NextAvailablePort()
|
||||
p2pPort := NextAvailablePort()
|
||||
zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
|
||||
node.NextAvailablePort())
|
||||
zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
|
||||
node.NextAvailablePort())
|
||||
rpcPort := node.NextAvailablePort()
|
||||
p2pPort := node.NextAvailablePort()
|
||||
|
||||
cmdArgs := []string{
|
||||
"-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
|
||||
// the log file before deleting the temporary log dir.
|
||||
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 {
|
||||
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/integration/rpctest"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
)
|
||||
|
||||
// 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
|
||||
// interface.
|
||||
var _ BackendConfig = (*BtcdBackendConfig)(nil)
|
||||
var _ node.BackendConfig = (*BtcdBackendConfig)(nil)
|
||||
|
||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||
// using this node as a chain backend.
|
||||
@@ -83,7 +84,7 @@ func (b BtcdBackendConfig) Name() string {
|
||||
func NewBackend(miner string, netParams *chaincfg.Params) (
|
||||
*BtcdBackendConfig, func() error, error) {
|
||||
|
||||
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir())
|
||||
baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
|
||||
args := []string{
|
||||
"--rejectnonstd",
|
||||
"--txindex",
|
||||
@@ -98,9 +99,12 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
||||
// Don't disconnect if a reply takes too long.
|
||||
"--nostalldetect",
|
||||
}
|
||||
chainBackend, err := rpctest.New(netParams, nil, args, GetBtcdBinary())
|
||||
chainBackend, err := rpctest.New(
|
||||
netParams, nil, args, node.GetBtcdBinary(),
|
||||
)
|
||||
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
|
||||
@@ -112,7 +116,8 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
||||
chainBackend.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
|
||||
|
||||
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{
|
||||
@@ -141,14 +146,16 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
|
||||
for _, file := range files {
|
||||
logFile := fmt.Sprintf("%s/%s", logDir, file.Name())
|
||||
newFilename := strings.Replace(
|
||||
file.Name(), "btcd.log", "output_btcd_chainbackend.log", 1,
|
||||
file.Name(), "btcd.log",
|
||||
"output_btcd_chainbackend.log", 1,
|
||||
)
|
||||
logDestination := fmt.Sprintf(
|
||||
"%s/%s", GetLogDir(), newFilename,
|
||||
"%s/%s", node.GetLogDir(), newFilename,
|
||||
)
|
||||
err := CopyFile(logDestination, logFile)
|
||||
err := node.CopyFile(logDestination, logFile)
|
||||
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"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
)
|
||||
|
||||
// NeutrinoBackendConfig is an implementation of the BackendConfig interface
|
||||
@@ -17,7 +18,7 @@ type NeutrinoBackendConfig struct {
|
||||
|
||||
// A compile time assertion to ensure NeutrinoBackendConfig meets the
|
||||
// BackendConfig interface.
|
||||
var _ BackendConfig = (*NeutrinoBackendConfig)(nil)
|
||||
var _ node.BackendConfig = (*NeutrinoBackendConfig)(nil)
|
||||
|
||||
// GenArgs returns the arguments needed to be passed to LND at startup for
|
||||
// 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