2021-09-14 08:15:04 +02:00
|
|
|
package lntest
|
|
|
|
|
|
|
|
import (
|
2021-09-18 07:00:39 +02:00
|
|
|
"errors"
|
2021-09-14 08:15:04 +02:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
2021-09-18 08:41:20 +02:00
|
|
|
"io"
|
2021-09-14 08:15:04 +02:00
|
|
|
"net"
|
2021-09-18 08:41:20 +02:00
|
|
|
"os"
|
2021-09-14 08:15:04 +02:00
|
|
|
"sync/atomic"
|
2021-09-18 07:00:39 +02:00
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
2021-09-14 08:15:04 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2022-01-06 12:51:37 +01:00
|
|
|
// ListenerFormat is the format string that is used to generate local
|
2021-09-14 08:15:04 +02:00
|
|
|
// listener addresses.
|
2022-01-06 12:51:37 +01:00
|
|
|
ListenerFormat = "127.0.0.1:%d"
|
2021-09-14 08:15:04 +02:00
|
|
|
|
|
|
|
// NeutrinoBackendName is the name of the neutrino backend.
|
|
|
|
NeutrinoBackendName = "neutrino"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DatabaseBackend int
|
|
|
|
|
|
|
|
const (
|
|
|
|
BackendBbolt DatabaseBackend = iota
|
|
|
|
BackendEtcd
|
|
|
|
BackendPostgres
|
|
|
|
)
|
|
|
|
|
|
|
|
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.
|
2022-07-22 02:44:07 +02:00
|
|
|
//
|
|
|
|
// TODO(yy): remove the export.
|
|
|
|
LogOutput = flag.Bool("logoutput", false,
|
2021-09-14 08:15:04 +02:00
|
|
|
"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.
|
2022-01-06 12:51:37 +01:00
|
|
|
addr := fmt.Sprintf(ListenerFormat, port)
|
2021-09-14 08:15:04 +02:00
|
|
|
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) {
|
2022-01-06 12:51:37 +01:00
|
|
|
return fmt.Sprintf(ListenerFormat, NextAvailablePort()),
|
|
|
|
fmt.Sprintf(ListenerFormat, NextAvailablePort())
|
2021-09-14 08:15:04 +02:00
|
|
|
}
|
2021-09-18 07:00:39 +02:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2021-09-18 08:41:20 +02:00
|
|
|
|
|
|
|
// 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()
|
|
|
|
}
|