some more changes

This commit is contained in:
rorp 2020-01-14 13:53:12 -08:00
parent 2f9d3606ca
commit 74fa1e61af
4 changed files with 113 additions and 60 deletions

View file

@ -21,28 +21,47 @@ object EclairBench extends App with EclairRpcTestUtil {
implicit val system = ActorSystem() implicit val system = ActorSystem()
import system.dispatcher import system.dispatcher
val networkSize = 1 // put compiled test jar files into binaries/eclair/${version} directory
val paymentCount = 10
val channelAmount = 10000000000L.msats
val outputFileName = "test.csv"
// release // None means current release
val EclairVersion = Option.empty[String] val TestEclairVersion = Option.empty[String]
val EclairCommit = Option.empty[String] val TestEclairCommit = Option.empty[String]
// val TestEclairVersion = Option("0.3.3-SNAPSHOT")
// val TestEclairCommit = Option("84825ff")
val SenderEclairVersion = Option.empty[String]
val SenderEclairCommit = Option.empty[String]
// psql val NetworkSize = 10
// compiled binary can be found here: val PaymentCount = 2000
// https://s3-us-west-1.amazonaws.com/suredbits.com/eclair/eclair-node-0.3.3-SNAPSHOT-949f1ec-psql.jar val ChannelAmount = 10000000000L.msats
// put it into binaries/eclair/0.3.3-SNAPSHOT directory val PaymentAmount = 10.msats
// val EclairVersion = Option("0.3.3-SNAPSHOT") val OutputFileName = "test.csv"
// val EclairCommit = Option("949f1ec-psql") val LogbackXml = None // Some("~/logback.xml")
// don't forget to recreate `eclair` Postgres database before starting a new test // don't forget to recreate `eclair` Postgres database before starting a new test
EclairRpcTestUtil.customConfigMap = Map( EclairRpcTestUtil.customConfigMap = Map(
"eclair.db.driver" -> "psql" "eclair.db.driver" -> "psql",
// "eclair.db.psql.pool.max-size" -> 12,
"eclair.db.psql.lock-type" -> "none"
// "eclair.db.psql.lock-type" -> "optimistic"
// "eclair.db.psql.lock-type" -> "exclusive"
) )
def sendPayments(network: Network, amount: MilliSatoshis, count: Int)( object Progress {
private var count = 0
private var percentage = 0
def inc(): Unit = synchronized {
count += 1
val newPercentage = count * 100 / (NetworkSize * PaymentCount)
if (newPercentage % 10 == 0 && newPercentage != percentage) {
percentage = newPercentage
print(s"$percentage% ")
}
}
}
def sendPayments(network: EclairNetwork, amount: MilliSatoshis, count: Int)(
implicit ec: ExecutionContext): Future[Vector[PaymentId]] = implicit ec: ExecutionContext): Future[Vector[PaymentId]] =
for { for {
testNodeInfo <- network.testEclairNode.getInfo testNodeInfo <- network.testEclairNode.getInfo
@ -64,25 +83,26 @@ object EclairBench extends App with EclairRpcTestUtil {
None) None)
} yield { } yield {
logPaymentId(paymentHash, id) logPaymentId(paymentHash, id)
Progress.inc()
acc :+ id acc :+ id
} }
} }
}) })
} yield paymentIds.flatten } yield paymentIds.flatten
def runTests(network: Network): Future[Vector[PaymentLogEntry]] = { def runTests(network: EclairNetwork): Future[Vector[PaymentLogEntry]] = {
println("Setting up the test network") println("Setting up the test network")
for { for {
_ <- network.testEclairNode.connectToWebSocket(logEvent) _ <- network.testEclairNode.connectToWebSocket(logEvent)
_ = println( _ = println(
s"Set up ${networkSize} nodes, that will send $paymentCount paments to the test node each") s"Set up ${NetworkSize} nodes, that will send $PaymentCount payments to the test node each")
_ = println( _ = println(
s"Test node data directory: ${network.testEclairNode.instance.authCredentials.datadir s"Test node data directory: ${network.testEclairNode.instance.authCredentials.datadir
.getOrElse("")}") .getOrElse("")}")
_ = println("Testing...") _ = println("Testing...")
_ <- sendPayments(network, 1000.msats, paymentCount) _ <- sendPayments(network, PaymentAmount, PaymentCount)
_ <- TestAsyncUtil.retryUntilSatisfied( _ <- TestAsyncUtil.retryUntilSatisfied(
condition = paymentLog.size() == networkSize * paymentCount, condition = paymentLog.size() == NetworkSize * PaymentCount,
duration = 1.second, duration = 1.second,
maxTries = 100) maxTries = 100)
_ <- TestAsyncUtil _ <- TestAsyncUtil
@ -90,7 +110,7 @@ object EclairBench extends App with EclairRpcTestUtil {
paymentLog.values().asScala.forall(_.completed), paymentLog.values().asScala.forall(_.completed),
duration = 1.second, duration = 1.second,
maxTries = 100) maxTries = 100)
_ = println("Done!") _ = println("\nDone!")
} yield { } yield {
paymentLog paymentLog
.values() .values()
@ -101,10 +121,13 @@ object EclairBench extends App with EclairRpcTestUtil {
} }
val res: Future[Unit] = for { val res: Future[Unit] = for {
network <- Network.start(EclairVersion, network <- EclairNetwork.start(TestEclairVersion,
EclairCommit, TestEclairCommit,
networkSize, SenderEclairVersion,
channelAmount) SenderEclairCommit,
NetworkSize,
ChannelAmount,
LogbackXml)
log <- runTests(network).recoverWith { log <- runTests(network).recoverWith {
case e: Throwable => case e: Throwable =>
e.printStackTrace() e.printStackTrace()
@ -122,7 +145,7 @@ object EclairBench extends App with EclairRpcTestUtil {
case (x, i) => case (x, i) =>
s"${x.paymentSentAt - first.paymentSentAt},${i + 1},${x.toCSV}" s"${x.paymentSentAt - first.paymentSentAt},${i + 1},${x.toCSV}"
} }
val outputFile = new File(outputFileName) val outputFile = new File(OutputFileName)
Files.write(outputFile.toPath, Files.write(outputFile.toPath,
csv.asJava, csv.asJava,
StandardOpenOption.CREATE, StandardOpenOption.CREATE,

View file

@ -704,10 +704,13 @@ class EclairRpcClient(val instance: EclairInstance, binary: Option[File] = None)
require(instance.authCredentials.datadir.isDefined, require(instance.authCredentials.datadir.isDefined,
s"A datadir needs to be provided to start eclair") s"A datadir needs to be provided to start eclair")
if (process.isEmpty) { if (process.isEmpty) {
val p = Process( val logback = instance.logbackXmlPath
s"java -jar -Declair.datadir=${instance.authCredentials.datadir.get} $pathToEclairJar &") .map(path => s"-Dlogback.configurationFile=$path")
.getOrElse("")
val cmd =
s"java -jar -Declair.datadir=${instance.authCredentials.datadir.get} $logback $pathToEclairJar &"
val p = Process(cmd)
val result = p.run() val result = p.run()
logger.debug( logger.debug(
s"Starting eclair with datadir ${instance.authCredentials.datadir.get}") s"Starting eclair with datadir ${instance.authCredentials.datadir.get}")

View file

@ -15,6 +15,7 @@ sealed trait EclairInstance {
def uri: URI def uri: URI
def rpcUri: URI def rpcUri: URI
def authCredentials: EclairAuthCredentials def authCredentials: EclairAuthCredentials
def logbackXmlPath: Option[String]
} }
/** /**
@ -29,57 +30,67 @@ object EclairInstance {
network: NetworkParameters, network: NetworkParameters,
uri: URI, uri: URI,
rpcUri: URI, rpcUri: URI,
authCredentials: EclairAuthCredentials) authCredentials: EclairAuthCredentials,
logbackXmlPath: Option[String])
extends EclairInstance extends EclairInstance
def apply( def apply(
network: NetworkParameters, network: NetworkParameters,
uri: URI, uri: URI,
rpcUri: URI, rpcUri: URI,
authCredentials: EclairAuthCredentials): EclairInstance = { authCredentials: EclairAuthCredentials,
EclairInstanceImpl(network, uri, rpcUri, authCredentials) logbackXmlPath: Option[String]): EclairInstance = {
EclairInstanceImpl(network, uri, rpcUri, authCredentials, logbackXmlPath)
} }
private val DEFAULT_DATADIR = Paths.get(Properties.userHome, ".eclair") private val DEFAULT_DATADIR = Paths.get(Properties.userHome, ".eclair")
private val DEFAULT_CONF_FILE = DEFAULT_DATADIR.resolve("eclair.conf") private val DEFAULT_CONF_FILE = DEFAULT_DATADIR.resolve("eclair.conf")
def fromDatadir(datadir: File = DEFAULT_DATADIR.toFile): EclairInstance = { def fromDatadir(
datadir: File = DEFAULT_DATADIR.toFile,
logbackXml: Option[String]): EclairInstance = {
require(datadir.exists, s"${datadir.getPath} does not exist!") require(datadir.exists, s"${datadir.getPath} does not exist!")
require(datadir.isDirectory, s"${datadir.getPath} is not a directory!") require(datadir.isDirectory, s"${datadir.getPath} is not a directory!")
val eclairConf = new File(datadir.getAbsolutePath + "/eclair.conf") val eclairConf = new File(datadir.getAbsolutePath + "/eclair.conf")
fromConfigFile(eclairConf) fromConfigFile(eclairConf, logbackXml)
} }
def fromConfigFile(file: File = DEFAULT_CONF_FILE.toFile): EclairInstance = { def fromConfigFile(
file: File = DEFAULT_CONF_FILE.toFile,
logbackXml: Option[String]): EclairInstance = {
require(file.exists, s"${file.getPath} does not exist!") require(file.exists, s"${file.getPath} does not exist!")
require(file.isFile, s"${file.getPath} is not a file!") require(file.isFile, s"${file.getPath} is not a file!")
val config = ConfigFactory.parseFile(file) val config = ConfigFactory.parseFile(file)
fromConfig(config, file.getParentFile) fromConfig(config, file.getParentFile, logbackXml)
} }
/** /**
* $fromConfigDoc * $fromConfigDoc
*/ */
def fromConfig(config: Config, datadir: File): EclairInstance = { def fromConfig(
fromConfig(config, Some(datadir)) config: Config,
datadir: File,
logbackXml: Option[String]): EclairInstance = {
fromConfig(config, Some(datadir), logbackXml)
} }
/** /**
* $fromConfigDoc * $fromConfigDoc
*/ */
def fromConfig(config: Config): EclairInstance = { def fromConfig(config: Config): EclairInstance = {
fromConfig(config, None) fromConfig(config, None, None)
} }
private def fromConfig( private def fromConfig(
config: Config, config: Config,
datadir: Option[File]): EclairInstance = { datadir: Option[File],
logbackXml: Option[String]): EclairInstance = {
val chain = ConfigUtil.getStringOrElse(config, "eclair.chain", "testnet") val chain = ConfigUtil.getStringOrElse(config, "eclair.chain", "testnet")
// default conf: https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf // default conf: https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf
@ -116,7 +127,8 @@ object EclairInstance {
val instance = EclairInstance(network = np, val instance = EclairInstance(network = np,
uri = uri, uri = uri,
rpcUri = rpcUri, rpcUri = rpcUri,
authCredentials = eclairAuth) authCredentials = eclairAuth,
logbackXml)
instance instance
} }

View file

@ -163,25 +163,32 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
} }
/** Assumes bitcoind is running already and you have specified correct bindings in eclair.conf */ /** Assumes bitcoind is running already and you have specified correct bindings in eclair.conf */
def cannonicalEclairInstance(): EclairInstance = { def cannonicalEclairInstance(
logbackXml: Option[String] = None): EclairInstance = {
val datadir = cannonicalDatadir val datadir = cannonicalDatadir
eclairInstance(datadir) eclairInstance(datadir, logbackXml)
} }
def eclairInstance(datadir: File): EclairInstance = { def eclairInstance(
val instance = EclairInstance.fromDatadir(datadir) datadir: File,
logbackXml: Option[String]): EclairInstance = {
val instance = EclairInstance.fromDatadir(datadir, logbackXml)
instance instance
} }
/** Starts the given bitcoind instance and then starts the eclair instance */ /** Starts the given bitcoind instance and then starts the eclair instance */
def eclairInstance(bitcoindRpc: BitcoindRpcClient): EclairInstance = { def eclairInstance(
bitcoindRpc: BitcoindRpcClient,
logbackXml: Option[String] = None): EclairInstance = {
val datadir = eclairDataDir(bitcoindRpc, false) val datadir = eclairDataDir(bitcoindRpc, false)
eclairInstance(datadir) eclairInstance(datadir, logbackXml)
} }
def randomEclairInstance(bitcoindRpc: BitcoindRpcClient): EclairInstance = { def randomEclairInstance(
bitcoindRpc: BitcoindRpcClient,
logbackXml: Option[String] = None): EclairInstance = {
val datadir = eclairDataDir(bitcoindRpc, false) val datadir = eclairDataDir(bitcoindRpc, false)
eclairInstance(datadir) eclairInstance(datadir, logbackXml)
} }
def randomEclairClient( def randomEclairClient(
@ -699,7 +706,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
shutdownF shutdownF
} }
case class Network( case class EclairNetwork(
bitcoind: BitcoindRpcClient, bitcoind: BitcoindRpcClient,
testEclairNode: EclairRpcClient, testEclairNode: EclairRpcClient,
networkEclairNodes: Vector[EclairRpcClient], networkEclairNodes: Vector[EclairRpcClient],
@ -713,31 +720,36 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
} yield () } yield ()
} }
object Network { object EclairNetwork {
def start( def start(
eclairVersion: Option[String], testEclairVersion: Option[String],
eclairCommit: Option[String], testEclairCommit: Option[String],
senderEclairVersion: Option[String],
senderEclairCommit: Option[String],
networkSize: Int, networkSize: Int,
channelAmount: MilliSatoshis)( channelAmount: MilliSatoshis,
implicit system: ActorSystem): Future[Network] = { logbackXml: Option[String])(
implicit system: ActorSystem): Future[EclairNetwork] = {
import system.dispatcher import system.dispatcher
for { for {
bitcoind <- startedBitcoindRpcClient() bitcoind <- startedBitcoindRpcClient()
testEclairInstance = EclairRpcTestUtil.eclairInstance(bitcoind) testEclairInstance = EclairRpcTestUtil.eclairInstance(bitcoind,
logbackXml =
logbackXml)
testEclairNode = new EclairRpcClient( testEclairNode = new EclairRpcClient(
testEclairInstance, testEclairInstance,
binary(eclairVersion, eclairCommit)) binary(testEclairVersion, testEclairCommit))
_ <- testEclairNode.start() _ <- testEclairNode.start()
_ <- awaitEclairInSync(testEclairNode, bitcoind) _ <- awaitEclairInSync(testEclairNode, bitcoind)
networkEclairInstances = 1 networkEclairInstances = 1
.to(networkSize) .to(networkSize)
.toVector .toVector
.map(_ => EclairRpcTestUtil.eclairInstance(bitcoind)) .map(_ =>
EclairRpcTestUtil.eclairInstance(bitcoind, logbackXml = logbackXml))
networkEclairNodes = networkEclairInstances.map( networkEclairNodes = networkEclairInstances.map(
new EclairRpcClient(_, new EclairRpcClient(_,
binary(Some(EclairRpcClient.version), binary(senderEclairVersion, senderEclairCommit)))
Some(EclairRpcClient.commit))))
_ <- Future.sequence(networkEclairNodes.map(_.start())) _ <- Future.sequence(networkEclairNodes.map(_.start()))
_ <- Future.sequence( _ <- Future.sequence(
networkEclairNodes.map(awaitEclairInSync(_, bitcoind))) networkEclairNodes.map(awaitEclairInSync(_, bitcoind)))
@ -756,7 +768,10 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
} }
_ <- Future.sequence( _ <- Future.sequence(
channelIds.map(awaitChannelOpened(testEclairNode, _))) channelIds.map(awaitChannelOpened(testEclairNode, _)))
} yield Network(bitcoind, testEclairNode, networkEclairNodes, channelIds) } yield EclairNetwork(bitcoind,
testEclairNode,
networkEclairNodes,
channelIds)
} }
} }