2022 04 26 Startup time of appServer (#4294)

* Make Server's route be async

* WIP

* Add StartedBitcoinSAppConfig to indicate when tor starts up

* Add torStarted flag to getinfo response
This commit is contained in:
Chris Stewart 2022-04-28 13:50:28 -05:00 committed by GitHub
parent 67f8ac8294
commit f4d864fab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 214 additions and 104 deletions

View File

@ -1,6 +1,7 @@
package org.bitcoins.commons.jsonmodels package org.bitcoins.commons.jsonmodels
import org.bitcoins.core.config.{BitcoinNetwork, BitcoinNetworks} import org.bitcoins.core.config.{BitcoinNetwork, BitcoinNetworks}
import org.bitcoins.core.serializers.PicklerKeys
import org.bitcoins.crypto.DoubleSha256DigestBE import org.bitcoins.crypto.DoubleSha256DigestBE
import ujson._ import ujson._
@ -8,13 +9,15 @@ import ujson._
case class BitcoinSServerInfo( case class BitcoinSServerInfo(
network: BitcoinNetwork, network: BitcoinNetwork,
blockHeight: Int, blockHeight: Int,
blockHash: DoubleSha256DigestBE) { blockHash: DoubleSha256DigestBE,
torStarted: Boolean) {
lazy val toJson: Value = { lazy val toJson: Value = {
Obj( Obj(
"network" -> Str(network.name), PicklerKeys.networkKey -> Str(network.name),
"blockHeight" -> Num(blockHeight), PicklerKeys.blockHeightKey -> Num(blockHeight),
"blockHash" -> Str(blockHash.hex) PicklerKeys.blockHashKey -> Str(blockHash.hex),
PicklerKeys.torStartedKey -> Bool(torStarted)
) )
} }
} }
@ -24,10 +27,14 @@ object BitcoinSServerInfo {
def fromJson(json: Value): BitcoinSServerInfo = { def fromJson(json: Value): BitcoinSServerInfo = {
val obj = json.obj val obj = json.obj
val network = BitcoinNetworks.fromString(obj("network").str) val network = BitcoinNetworks.fromString(obj(PicklerKeys.networkKey).str)
val height = obj("blockHeight").num.toInt val height = obj(PicklerKeys.blockHeightKey).num.toInt
val blockHash = DoubleSha256DigestBE(obj("blockHash").str) val blockHash = DoubleSha256DigestBE(obj(PicklerKeys.blockHashKey).str)
val torStarted = obj(PicklerKeys.torStartedKey).bool
BitcoinSServerInfo(network, height, blockHash) BitcoinSServerInfo(network = network,
blockHeight = height,
blockHash = blockHash,
torStarted = torStarted)
} }
} }

View File

@ -27,11 +27,11 @@ class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit
for { for {
_ <- conf.start() _ <- conf.start()
oracle = new DLCOracle() oracle = new DLCOracle()
routes = Seq(OracleRoutes(oracle), commonRoutes) routes = Seq(OracleRoutes(oracle), commonRoutes).map(Future.successful)
server = serverArgParser.rpcPortOpt match { server = serverArgParser.rpcPortOpt match {
case Some(rpcport) => case Some(rpcport) =>
Server(conf = conf, Server(conf = conf,
handlers = routes, handlersF = routes,
rpcbindOpt = bindConfOpt, rpcbindOpt = bindConfOpt,
rpcport = rpcport, rpcport = rpcport,
rpcPassword = conf.rpcPassword, rpcPassword = conf.rpcPassword,
@ -39,7 +39,7 @@ class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit
Source.empty) Source.empty)
case None => case None =>
Server(conf = conf, Server(conf = conf,
handlers = routes, handlersF = routes,
rpcbindOpt = bindConfOpt, rpcbindOpt = bindConfOpt,
rpcport = conf.rpcPort, rpcport = conf.rpcPort,
rpcPassword = conf.rpcPassword, rpcPassword = conf.rpcPassword,

View File

@ -8,7 +8,14 @@ import akka.http.scaladsl.model.ws.Message
import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._ import akka.http.scaladsl.server._
import akka.http.scaladsl.server.directives.Credentials.Missing import akka.http.scaladsl.server.directives.Credentials.Missing
import akka.http.scaladsl.server.directives.{Credentials, DebuggingDirectives} import akka.http.scaladsl.server.directives.{
Credentials,
DebuggingDirectives,
MarshallingDirectives,
MethodDirectives,
PathDirectives
}
import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller
import akka.stream.scaladsl.{Flow, Sink, Source} import akka.stream.scaladsl.{Flow, Sink, Source}
import akka.{Done, NotUsed} import akka.{Done, NotUsed}
import de.heikoseeberger.akkahttpupickle.UpickleSupport._ import de.heikoseeberger.akkahttpupickle.UpickleSupport._
@ -20,7 +27,7 @@ import scala.concurrent.Future
case class Server( case class Server(
conf: AppConfig, conf: AppConfig,
handlers: Seq[ServerRoute], handlersF: Seq[Future[ServerRoute]],
rpcbindOpt: Option[String], rpcbindOpt: Option[String],
rpcport: Int, rpcport: Int,
rpcPassword: String, rpcPassword: String,
@ -86,29 +93,64 @@ case class Server(
} }
} }
private val serverCmdDirective: FromRequestUnmarshaller[ServerCommand] =
MarshallingDirectives.as[ServerCommand]
private val initF =
Future.successful(PartialFunction.empty[ServerCommand, Route])
private def handlerF: Future[PartialFunction[ServerCommand, Route]] = {
handlersF.foldLeft(initF) { case (accumF, currF) =>
for {
accum <- accumF
newAccum <-
if (currF.isCompleted) {
currF.map(curr => accum.orElse(curr.handleCommand))
} else {
Future.successful(accum)
}
} yield {
newAccum
}
}
}
val route: Route = { val route: Route = {
val commonRoute = withErrorHandling { val commonRoute: Route = {
pathSingleSlash { withErrorHandling {
post { PathDirectives.pathSingleSlash {
entity(as[ServerCommand]) { cmd => MethodDirectives.post { ctx =>
val init = PartialFunction.empty[ServerCommand, Route] val route: Future[Route] = {
val handler = handlers.foldLeft(init) { case (accum, curr) => for {
accum.orElse(curr.handleCommand) handler <- handlerF
} yield {
MarshallingDirectives.entity(serverCmdDirective) { cmd =>
val i = handler.orElse(catchAllHandler).apply(cmd)
i
}
}
} }
handler.orElse(catchAllHandler).apply(cmd) route.flatMap(_.apply(ctx))
} }
} }
} }
} }
val authenticatedRoute = if (rpcPassword.isEmpty) { val authDirectiveOpt: Option[Directive1[Done]] = {
commonRoute if (rpcPassword.isEmpty) {
} else { None
authenticateBasic("auth", authenticator) { _ => } else {
commonRoute Some(authenticateBasic("auth", authenticator))
} }
} }
val authenticatedRoute: Route = authDirectiveOpt match {
case Some(authDirective) =>
authDirective { case _ =>
commonRoute
}
case None => commonRoute
}
DebuggingDirectives.logRequestResult( DebuggingDirectives.logRequestResult(
("http-rpc-server", Logging.DebugLevel)) { ("http-rpc-server", Logging.DebugLevel)) {
@ -117,10 +159,12 @@ case class Server(
} }
def start(): Future[ServerBindings] = { def start(): Future[ServerBindings] = {
val httpFut = val httpFut = for {
Http() http <- Http()
.newServerAt(rpchost, rpcport) .newServerAt(rpchost, rpcport)
.bindFlow(route) .bindFlow(route)
} yield http
httpFut.foreach { http => httpFut.foreach { http =>
logger.info(s"Started Bitcoin-S HTTP server at ${http.localAddress}") logger.info(s"Started Bitcoin-S HTTP server at ${http.localAddress}")
} }

View File

@ -0,0 +1,16 @@
package org.bitcoins.server.util
import scala.concurrent.Future
/** A trait used to indicated when different parts of [[BitcoinSAppConfig]] are started */
sealed trait AppConfigMarker
/** This class represents when BitcoinSAppConfig modules are started
* @param torStartedF this future is completed when all tor dependent modules are fully started
* the reason this is needed is because tor startup time is so variable
* @see https://github.com/bitcoin-s/bitcoin-s/issues/4210
*/
case class StartedBitcoinSAppConfig(torStartedF: Future[Unit])
extends AppConfigMarker
case object StoppedBitcoinSAppConfig extends AppConfigMarker

View File

@ -67,7 +67,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
val mockNode = mock[Node] val mockNode = mock[Node]
val chainRoutes = ChainRoutes(mockChainApi, RegTest) val chainRoutes = ChainRoutes(mockChainApi, RegTest, Future.unit)
val nodeRoutes = NodeRoutes(mockNode) val nodeRoutes = NodeRoutes(mockNode)

View File

@ -13,6 +13,11 @@ import org.bitcoins.dlc.wallet.DLCAppConfig
import org.bitcoins.keymanager.config.KeyManagerAppConfig import org.bitcoins.keymanager.config.KeyManagerAppConfig
import org.bitcoins.node.config.NodeAppConfig import org.bitcoins.node.config.NodeAppConfig
import org.bitcoins.rpc.config.BitcoindRpcAppConfig import org.bitcoins.rpc.config.BitcoindRpcAppConfig
import org.bitcoins.server.util.{
AppConfigMarker,
StartedBitcoinSAppConfig,
StoppedBitcoinSAppConfig
}
import org.bitcoins.tor.config.TorAppConfig import org.bitcoins.tor.config.TorAppConfig
import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.config.WalletAppConfig
@ -33,7 +38,7 @@ import scala.concurrent.duration.{DurationInt, FiniteDuration}
case class BitcoinSAppConfig( case class BitcoinSAppConfig(
baseDatadir: Path, baseDatadir: Path,
configOverrides: Vector[Config])(implicit system: ActorSystem) configOverrides: Vector[Config])(implicit system: ActorSystem)
extends StartStopAsync[Unit] extends StartStopAsync[AppConfigMarker]
with Logging { with Logging {
import system.dispatcher import system.dispatcher
@ -65,7 +70,7 @@ case class BitcoinSAppConfig(
lazy val network: NetworkParameters = chainConf.network lazy val network: NetworkParameters = chainConf.network
/** Initializes the wallet, node and chain projects */ /** Initializes the wallet, node and chain projects */
override def start(): Future[Unit] = { override def start(): Future[StartedBitcoinSAppConfig] = {
val start = TimeUtil.currentEpochMs val start = TimeUtil.currentEpochMs
//configurations that don't depend on tor startup //configurations that don't depend on tor startup
//start these in parallel as an optimization //start these in parallel as an optimization
@ -83,22 +88,23 @@ case class BitcoinSAppConfig(
for { for {
_ <- startedNonTorConfigs _ <- startedNonTorConfigs
_ <- startedTorDependentConfigsF
} yield { } yield {
logger.info( logger.info(
s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms") s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms")
() StartedBitcoinSAppConfig(startedTorDependentConfigsF.map(_ => ()))
} }
} }
override def stop(): Future[Unit] = { override def stop(): Future[StoppedBitcoinSAppConfig.type] = {
for { for {
_ <- nodeConf.stop() _ <- nodeConf.stop()
_ <- walletConf.stop() _ <- walletConf.stop()
_ <- chainConf.stop() _ <- chainConf.stop()
_ <- bitcoindRpcConf.stop() _ <- bitcoindRpcConf.stop()
_ <- torConf.stop() _ <- torConf.stop()
} yield () } yield {
StoppedBitcoinSAppConfig
}
} }
/** The underlying config the result of our fields derive from */ /** The underlying config the result of our fields derive from */

View File

@ -77,13 +77,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
} }
for { for {
_ <- startedConfigF startedConfig <- startedConfigF
start <- { start <- {
nodeConf.nodeType match { nodeConf.nodeType match {
case _: InternalImplementationNodeType => case _: InternalImplementationNodeType =>
startBitcoinSBackend() startBitcoinSBackend(startedConfig.torStartedF)
case NodeType.BitcoindBackend => case NodeType.BitcoindBackend =>
startBitcoindBackend() startBitcoindBackend(startedConfig.torStartedF)
} }
} }
} yield { } yield {
@ -107,7 +107,11 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
} }
} }
def startBitcoinSBackend(): Future[Unit] = { /** Start the bitcoin-s wallet server with a neutrino backend
* @param startedTorConfigF a future that is completed when tor is fully started
* @return
*/
def startBitcoinSBackend(startedTorConfigF: Future[Unit]): Future[Unit] = {
logger.info(s"startBitcoinSBackend()") logger.info(s"startBitcoinSBackend()")
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
@ -174,27 +178,29 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
val startedDLCNodeF = dlcNodeF val startedDLCNodeF = dlcNodeF
.flatMap(_.start()) .flatMap(_.start())
.flatMap(_ => dlcNodeF) .flatMap(_ => dlcNodeF)
val chainApi = ChainHandler.fromDatabase()
//start our http server now that we are synced //start our http server now that we are synced
for { for {
wallet <- configuredWalletF _ <- startHttpServer(
node <- startedNodeF nodeApiF = startedNodeF,
_ <- startedWalletF chainApi = chainApi,
cachedChainApi <- node.chainApiFromDb() walletF = configuredWalletF,
chainApi = ChainHandler.fromChainHandlerCached(cachedChainApi) dlcNodeF = startedDLCNodeF,
dlcNode <- startedDLCNodeF torConfStarted = startedTorConfigF,
_ <- startHttpServer(nodeApi = node, serverCmdLineArgs = serverArgParser,
chainApi = chainApi, wsSource = wsSource
wallet = wallet, )
dlcNode = dlcNode,
serverCmdLineArgs = serverArgParser,
wsSource = wsSource)
_ = { _ = {
logger.info( logger.info(
s"Starting ${nodeConf.nodeType.shortName} node sync, it took=${System s"Starting ${nodeConf.nodeType.shortName} node sync, it took=${System
.currentTimeMillis() - start}ms") .currentTimeMillis() - start}ms")
} }
_ <- startedWalletF
//make sure callbacks are registered before we start sync //make sure callbacks are registered before we start sync
_ <- callbacksF _ <- callbacksF
node <- startedNodeF
_ <- startedTorConfigF
_ <- node.sync() _ <- node.sync()
} yield { } yield {
logger.info( logger.info(
@ -235,14 +241,22 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
} yield info } yield info
} }
def startBitcoindBackend(): Future[Unit] = { /** Start the bitcoin-s wallet server with a bitcoind backend
* @param startedTorConfigF a future that is completed when tor is fully started
* @return
*/
def startBitcoindBackend(startedTorConfigF: Future[Unit]): Future[Unit] = {
logger.info(s"startBitcoindBackend()") logger.info(s"startBitcoindBackend()")
val bitcoindF = for { val bitcoindF = for {
client <- bitcoindRpcConf.clientF client <- bitcoindRpcConf.clientF
_ <- client.start() _ <- client.start()
} yield client } yield client
val tmpWalletF = bitcoindF.flatMap { bitcoind => val tuple = buildWsSource
val wsQueue: SourceQueueWithComplete[Message] = tuple._1
val wsSource: Source[Message, NotUsed] = tuple._2
val walletF = bitcoindF.flatMap { bitcoind =>
val feeProvider = FeeProviderFactory.getFeeProviderOrElse( val feeProvider = FeeProviderFactory.getFeeProviderOrElse(
bitcoind, bitcoind,
feeProviderNameStrOpt = walletConf.feeProviderNameOpt, feeProviderNameStrOpt = walletConf.feeProviderNameOpt,
@ -250,14 +264,38 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
proxyParamsOpt = walletConf.torConf.socks5ProxyParams, proxyParamsOpt = walletConf.torConf.socks5ProxyParams,
network = walletConf.network network = walletConf.network
) )
dlcConf.createDLCWallet(nodeApi = bitcoind, logger.info("Creating wallet")
chainQueryApi = bitcoind, val tmpWalletF = dlcConf.createDLCWallet(nodeApi = bitcoind,
feeRateApi = feeProvider) chainQueryApi = bitcoind,
feeRateApi = feeProvider)
val chainCallbacks = WebsocketUtil.buildChainCallbacks(wsQueue, bitcoind)
for {
tmpWallet <- tmpWalletF
wallet = BitcoindRpcBackendUtil.createDLCWalletWithBitcoindCallbacks(
bitcoind,
tmpWallet,
Some(chainCallbacks))
nodeCallbacks <- CallbackUtil.createBitcoindNodeCallbacksForWallet(
wallet)
_ = nodeConf.addCallbacks(nodeCallbacks)
_ = logger.info("Starting wallet")
_ <- wallet.start().recoverWith {
//https://github.com/bitcoin-s/bitcoin-s/issues/2917
//https://github.com/bitcoin-s/bitcoin-s/pull/2918
case err: IllegalArgumentException
if err.getMessage.contains("If we have spent a spendinginfodb") =>
handleMissingSpendingInfoDb(err, wallet)
}
} yield wallet
} }
val tuple = buildWsSource val dlcNodeF = {
val wsQueue: SourceQueueWithComplete[Message] = tuple._1 for {
val wsSource: Source[Message, NotUsed] = tuple._2 wallet <- walletF
dlcNode = dlcNodeConf.createDLCNode(wallet)
_ <- dlcNode.start()
} yield dlcNode
}
for { for {
_ <- bitcoindRpcConf.start() _ <- bitcoindRpcConf.start()
@ -268,42 +306,26 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
_ = require( _ = require(
bitcoindNetwork == walletConf.network, bitcoindNetwork == walletConf.network,
s"bitcoind ($bitcoindNetwork) on different network than wallet (${walletConf.network})") s"bitcoind ($bitcoindNetwork) on different network than wallet (${walletConf.network})")
_ <- startHttpServer(
_ = logger.info("Creating wallet") nodeApiF = Future.successful(bitcoind),
chainCallbacks = WebsocketUtil.buildChainCallbacks(wsQueue, bitcoind) chainApi = bitcoind,
tmpWallet <- tmpWalletF walletF = walletF,
wallet = BitcoindRpcBackendUtil.createDLCWalletWithBitcoindCallbacks( dlcNodeF = dlcNodeF,
bitcoind, torConfStarted = startedTorConfigF,
tmpWallet, serverCmdLineArgs = serverArgParser,
Some(chainCallbacks)) wsSource = wsSource
nodeCallbacks <- CallbackUtil.createBitcoindNodeCallbacksForWallet(wallet) )
_ = nodeConf.addCallbacks(nodeCallbacks)
_ = logger.info("Starting wallet")
_ <- wallet.start().recoverWith {
//https://github.com/bitcoin-s/bitcoin-s/issues/2917
//https://github.com/bitcoin-s/bitcoin-s/pull/2918
case err: IllegalArgumentException
if err.getMessage.contains("If we have spent a spendinginfodb") =>
handleMissingSpendingInfoDb(err, wallet)
}
dlcNode = dlcNodeConf.createDLCNode(wallet)
_ <- dlcNode.start()
_ <- startHttpServer(nodeApi = bitcoind,
chainApi = bitcoind,
wallet = wallet,
dlcNode = dlcNode,
serverCmdLineArgs = serverArgParser,
wsSource = wsSource)
walletCallbacks = WebsocketUtil.buildWalletCallbacks(wsQueue) walletCallbacks = WebsocketUtil.buildWalletCallbacks(wsQueue)
_ = walletConf.addCallbacks(walletCallbacks) _ = walletConf.addCallbacks(walletCallbacks)
wallet <- walletF
//intentionally doesn't map on this otherwise we //intentionally doesn't map on this otherwise we
//wait until we are done syncing the entire wallet //wait until we are done syncing the entire wallet
//which could take 1 hour //which could take 1 hour
_ = syncWalletWithBitcoindAndStartPolling(bitcoind, wallet) _ = syncWalletWithBitcoindAndStartPolling(bitcoind, wallet)
dlcWalletCallbacks = WebsocketUtil.buildDLCWalletCallbacks(wsQueue) dlcWalletCallbacks = WebsocketUtil.buildDLCWalletCallbacks(wsQueue)
_ = dlcConf.addCallbacks(dlcWalletCallbacks) _ = dlcConf.addCallbacks(dlcWalletCallbacks)
_ <- startedTorConfigF
} yield { } yield {
logger.info(s"Done starting Main!") logger.info(s"Done starting Main!")
() ()
@ -351,10 +373,11 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
private var serverBindingsOpt: Option[ServerBindings] = None private var serverBindingsOpt: Option[ServerBindings] = None
private def startHttpServer( private def startHttpServer(
nodeApi: NodeApi, nodeApiF: Future[NodeApi],
chainApi: ChainApi, chainApi: ChainApi,
wallet: DLCWallet, walletF: Future[DLCWallet],
dlcNode: DLCNode, dlcNodeF: Future[DLCNode],
torConfStarted: Future[Unit],
serverCmdLineArgs: ServerArgParser, serverCmdLineArgs: ServerArgParser,
wsSource: Source[Message, NotUsed])(implicit wsSource: Source[Message, NotUsed])(implicit
system: ActorSystem, system: ActorSystem,
@ -362,20 +385,21 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
implicit val nodeConf: NodeAppConfig = conf.nodeConf implicit val nodeConf: NodeAppConfig = conf.nodeConf
implicit val walletConf: WalletAppConfig = conf.walletConf implicit val walletConf: WalletAppConfig = conf.walletConf
val walletRoutes = WalletRoutes(wallet) val walletRoutesF = walletF.map(WalletRoutes(_))
val nodeRoutes = NodeRoutes(nodeApi) val nodeRoutesF = nodeApiF.map(NodeRoutes(_))
val chainRoutes = ChainRoutes(chainApi, nodeConf.network) val chainRoutes =
ChainRoutes(chainApi, nodeConf.network, torConfStarted)
val coreRoutes = CoreRoutes() val coreRoutes = CoreRoutes()
val dlcRoutes = DLCRoutes(dlcNode) val dlcRoutesF = dlcNodeF.map(DLCRoutes(_))
val commonRoutes = CommonRoutes(conf.baseDatadir) val commonRoutes = CommonRoutes(conf.baseDatadir)
val handlers = val handlers =
Seq(walletRoutes, Seq(walletRoutesF,
nodeRoutes, nodeRoutesF,
chainRoutes, Future.successful(chainRoutes),
coreRoutes, Future.successful(coreRoutes),
dlcRoutes, dlcRoutesF,
commonRoutes) Future.successful(commonRoutes))
val rpcBindConfOpt = serverCmdLineArgs.rpcBindOpt match { val rpcBindConfOpt = serverCmdLineArgs.rpcBindOpt match {
case Some(rpcbind) => Some(rpcbind) case Some(rpcbind) => Some(rpcbind)
@ -399,7 +423,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
serverCmdLineArgs.rpcPortOpt match { serverCmdLineArgs.rpcPortOpt match {
case Some(rpcport) => case Some(rpcport) =>
Server(conf = nodeConf, Server(conf = nodeConf,
handlers = handlers, handlersF = handlers,
rpcbindOpt = rpcBindConfOpt, rpcbindOpt = rpcBindConfOpt,
rpcport = rpcport, rpcport = rpcport,
rpcPassword = conf.rpcPassword, rpcPassword = conf.rpcPassword,
@ -408,7 +432,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
case None => case None =>
Server( Server(
conf = nodeConf, conf = nodeConf,
handlers = handlers, handlersF = handlers,
rpcbindOpt = rpcBindConfOpt, rpcbindOpt = rpcBindConfOpt,
rpcport = conf.rpcPort, rpcport = conf.rpcPort,
rpcPassword = conf.rpcPassword, rpcPassword = conf.rpcPassword,

View File

@ -13,8 +13,10 @@ import org.bitcoins.server.util.ChainUtil
import scala.concurrent.Future import scala.concurrent.Future
case class ChainRoutes(chain: ChainApi, network: BitcoinNetwork)(implicit case class ChainRoutes(
system: ActorSystem) chain: ChainApi,
network: BitcoinNetwork,
startedTorConfigF: Future[Unit])(implicit system: ActorSystem)
extends ServerRoute { extends ServerRoute {
import system.dispatcher import system.dispatcher
@ -67,7 +69,11 @@ case class ChainRoutes(chain: ChainApi, network: BitcoinNetwork)(implicit
case ServerCommand("getinfo", _) => case ServerCommand("getinfo", _) =>
complete { complete {
chain.getBestBlockHeader().map { header => chain.getBestBlockHeader().map { header =>
val info = BitcoinSServerInfo(network, header.height, header.hashBE) val info = BitcoinSServerInfo(network = network,
blockHeight = header.height,
blockHash = header.hashBE,
torStarted =
startedTorConfigF.isCompleted)
Server.httpSuccess(info.toJson) Server.httpSuccess(info.toJson)
} }

View File

@ -32,6 +32,8 @@ object PicklerKeys {
final val chainworkKey: String = "chainwork" final val chainworkKey: String = "chainwork"
final val previousblockhashKey: String = "previousblockhash" final val previousblockhashKey: String = "previousblockhash"
final val nextblockhashKey: String = "nextblockhash" final val nextblockhashKey: String = "nextblockhash"
final val blockHashKey: String = "blockHash"
final val blockHeightKey: String = "blockHeight"
final val myCollateral: String = "myCollateral" final val myCollateral: String = "myCollateral"
final val theirCollateral: String = "theirCollateral" final val theirCollateral: String = "theirCollateral"
final val myPayout: String = "myPayout" final val myPayout: String = "myPayout"
@ -39,10 +41,14 @@ object PicklerKeys {
final val pnl: String = "pnl" final val pnl: String = "pnl"
final val rateOfReturn: String = "rateOfReturn" final val rateOfReturn: String = "rateOfReturn"
final val networkKey: String = "network"
final val outcomeKey: String = "outcome" final val outcomeKey: String = "outcome"
final val localPayoutKey: String = "localPayout" final val localPayoutKey: String = "localPayout"
final val outcomesKey: String = "outcomes" final val outcomesKey: String = "outcomes"
final val torStartedKey: String = "torStarted"
//tlv points //tlv points
final val pointsKey = "points" final val pointsKey = "points"
final val payoutKey: String = "payout" final val payoutKey: String = "payout"

View File

@ -39,6 +39,7 @@ trait CachedBitcoinSAppConfig { _: BitcoinSAkkaAsyncTest =>
override def afterAll(): Unit = { override def afterAll(): Unit = {
Await.result(cachedConfig.stop(), duration) Await.result(cachedConfig.stop(), duration)
()
} }
} }