mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-19 01:43:22 +01:00
Use sttp lib instead of akka-http-client (#720)
Also updated json4s-jackson to 3.6.0
This commit is contained in:
parent
5141cd7d4d
commit
2de7c6b07d
@ -126,22 +126,34 @@
|
||||
<artifactId>akka-slf4j_${scala.version.short}</artifactId>
|
||||
<version>${akka.version}</version>
|
||||
</dependency>
|
||||
<!-- HTTP SERVER -->
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http-core_${scala.version.short}</artifactId>
|
||||
<version>10.0.11</version>
|
||||
</dependency>
|
||||
<!-- HTTP CLIENT -->
|
||||
<dependency>
|
||||
<groupId>com.softwaremill.sttp</groupId>
|
||||
<artifactId>async-http-client-backend-future_${scala.version.short}</artifactId>
|
||||
<version>${sttp.version}</version>
|
||||
</dependency>
|
||||
<!-- JSON -->
|
||||
<dependency>
|
||||
<groupId>org.json4s</groupId>
|
||||
<artifactId>json4s-jackson_${scala.version.short}</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<version>3.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.heikoseeberger</groupId>
|
||||
<artifactId>akka-http-json4s_${scala.version.short}</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.softwaremill.sttp</groupId>
|
||||
<artifactId>json4s_${scala.version.short}</artifactId>
|
||||
<version>${sttp.version}</version>
|
||||
</dependency>
|
||||
<!-- BITCOIN -->
|
||||
<dependency>
|
||||
<groupId>fr.acinq</groupId>
|
||||
|
@ -24,6 +24,7 @@ import akka.http.scaladsl.Http
|
||||
import akka.pattern.after
|
||||
import akka.stream.{ActorMaterializer, BindFailedException}
|
||||
import akka.util.Timeout
|
||||
import com.softwaremill.sttp.asynchttpclient.future.AsyncHttpClientFutureBackend
|
||||
import com.typesafe.config.{Config, ConfigFactory}
|
||||
import fr.acinq.bitcoin.{BinaryData, Block}
|
||||
import fr.acinq.eclair.NodeParams.{BITCOIND, ELECTRUM}
|
||||
@ -81,10 +82,8 @@ class Setup(datadir: File,
|
||||
// this will force the secure random instance to initialize itself right now, making sure it doesn't hang later (see comment in package.scala)
|
||||
secureRandom.nextInt()
|
||||
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
implicit val formats = org.json4s.DefaultFormats
|
||||
implicit val ec = ExecutionContext.Implicits.global
|
||||
implicit val sttpBackend = AsyncHttpClientFutureBackend()
|
||||
|
||||
val bitcoin = nodeParams.watcherType match {
|
||||
case BITCOIND =>
|
||||
@ -93,6 +92,8 @@ class Setup(datadir: File,
|
||||
password = config.getString("bitcoind.rpcpassword"),
|
||||
host = config.getString("bitcoind.host"),
|
||||
port = config.getInt("bitcoind.rpcport"))
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
implicit val formats = org.json4s.DefaultFormats
|
||||
val future = for {
|
||||
json <- bitcoinClient.invoke("getblockchaininfo").recover { case _ => throw BitcoinRPCConnectionException }
|
||||
// Make sure wallet support is enabled in bitcoind.
|
||||
@ -192,6 +193,7 @@ class Setup(datadir: File,
|
||||
case Bitcoind(bitcoinClient) => new BitcoinCoreWallet(bitcoinClient)
|
||||
case Electrum(electrumClient) =>
|
||||
val electrumWallet = system.actorOf(ElectrumWallet.props(seed, electrumClient, ElectrumWallet.WalletParameters(nodeParams.chainHash)), "electrum-wallet")
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
new ElectrumEclairWallet(electrumWallet, nodeParams.chainHash)
|
||||
}
|
||||
_ = wallet.getFinalAddress.map {
|
||||
@ -233,6 +235,7 @@ class Setup(datadir: File,
|
||||
_ <- Future.firstCompletedOf(tcpBound.future :: tcpTimeout :: Nil)
|
||||
_ <- if (config.getBoolean("api.enabled")) {
|
||||
logger.info(s"json-rpc api enabled on port=${config.getInt("api.port")}")
|
||||
implicit val materializer = ActorMaterializer()
|
||||
val api = new Service {
|
||||
|
||||
override def scheduler = system.scheduler
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package fr.acinq.eclair.blockchain.bitcoind
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.blockchain._
|
||||
@ -30,11 +29,10 @@ import scala.concurrent.{ExecutionContext, Future}
|
||||
/**
|
||||
* Created by PM on 06/07/2017.
|
||||
*/
|
||||
class BitcoinCoreWallet(rpcClient: BitcoinJsonRPCClient)(implicit system: ActorSystem, ec: ExecutionContext) extends EclairWallet with Logging {
|
||||
class BitcoinCoreWallet(rpcClient: BitcoinJsonRPCClient)(implicit ec: ExecutionContext) extends EclairWallet with Logging {
|
||||
|
||||
import BitcoinCoreWallet._
|
||||
|
||||
|
||||
def fundTransaction(hex: String, lockUnspents: Boolean, feeRatePerKw: Long): Future[FundTransactionResponse] = {
|
||||
val feeRatePerKB = BigDecimal(feerateKw2KB(feeRatePerKw))
|
||||
rpcClient.invoke("fundrawtransaction", hex, Options(lockUnspents, feeRatePerKB.bigDecimal.scaleByPowerOfTen(-8))).map(json => {
|
||||
|
@ -16,52 +16,19 @@
|
||||
|
||||
package fr.acinq.eclair.blockchain.bitcoind.rpc
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.event.Logging
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.marshalling.Marshal
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.http.scaladsl.model.headers.{Authorization, BasicHttpCredentials}
|
||||
import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||
import akka.stream.scaladsl.{Keep, Sink, Source}
|
||||
import akka.stream.{ActorMaterializer, OverflowStrategy, QueueOfferResult}
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
|
||||
import com.softwaremill.sttp._
|
||||
import com.softwaremill.sttp.json4s._
|
||||
import org.json4s.DefaultFormats
|
||||
import org.json4s.JsonAST.JValue
|
||||
import org.json4s.{DefaultFormats, jackson}
|
||||
import org.json4s.jackson.Serialization
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.{ExecutionContext, Future, Promise}
|
||||
import scala.util.{Failure, Success}
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false)(implicit system: ActorSystem) extends BitcoinJsonRPCClient {
|
||||
class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false)(implicit http: SttpBackend[Future, Nothing]) extends BitcoinJsonRPCClient {
|
||||
|
||||
val scheme = if (ssl) "https" else "http"
|
||||
val uri = Uri(s"$scheme://$host:$port")
|
||||
implicit val serialization = jackson.Serialization
|
||||
implicit val formats = DefaultFormats.withBigDecimal
|
||||
val log = Logging(system, classOf[BasicBitcoinJsonRPCClient])
|
||||
|
||||
implicit val materializer = ActorMaterializer()
|
||||
val httpClientFlow = Http().cachedHostConnectionPool[Promise[HttpResponse]](host, port)
|
||||
|
||||
val queueSize = 256
|
||||
val queue = Source.queue[(HttpRequest, Promise[HttpResponse])](queueSize, OverflowStrategy.dropNew)
|
||||
.via(httpClientFlow)
|
||||
.toMat(Sink.foreach({
|
||||
case ((Success(resp), p)) => p.success(resp)
|
||||
case ((Failure(e), p)) => p.failure(e)
|
||||
}))(Keep.left)
|
||||
.run()
|
||||
|
||||
def queueRequest(request: HttpRequest): Future[HttpResponse] = {
|
||||
val responsePromise = Promise[HttpResponse]()
|
||||
queue.offer(request -> responsePromise).flatMap {
|
||||
case QueueOfferResult.Enqueued => responsePromise.future
|
||||
case QueueOfferResult.Dropped => Future.failed(new RuntimeException("Queue overflowed. Try again later."))
|
||||
case QueueOfferResult.Failure(ex) => Future.failed(ex)
|
||||
case QueueOfferResult.QueueClosed => Future.failed(new RuntimeException("Queue was closed (pool shut down) while running the request. Try again later."))
|
||||
}
|
||||
}
|
||||
implicit val serialization = Serialization
|
||||
|
||||
override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] =
|
||||
invoke(Seq(JsonRPCRequest(method = method, params = params))).map(l => jsonResponse2Exception(l.head).result)
|
||||
@ -73,12 +40,12 @@ class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = "
|
||||
|
||||
def invoke(requests: Seq[JsonRPCRequest])(implicit ec: ExecutionContext): Future[Seq[JsonRPCResponse]] =
|
||||
for {
|
||||
entity <- Marshal(requests).to[RequestEntity]
|
||||
_ = log.debug("sending rpc request with body={}", entity)
|
||||
httpRes <- queueRequest(HttpRequest(uri = "/", method = HttpMethods.POST).addHeader(Authorization(BasicHttpCredentials(user, password))).withEntity(entity))
|
||||
jsonRpcRes <- Unmarshal(httpRes).to[Seq[JsonRPCResponse]].recover {
|
||||
case t: Throwable if httpRes.status == StatusCodes.Unauthorized => throw new RuntimeException("bitcoind replied with 401/Unauthorized (bad user/password?)", t)
|
||||
}
|
||||
} yield jsonRpcRes
|
||||
res <- sttp
|
||||
.post(uri"$scheme://$host:$port")
|
||||
.body(requests)
|
||||
.auth.basic(user, password)
|
||||
.response(asJson[Seq[JsonRPCResponse]])
|
||||
.send()
|
||||
} yield res.unsafeBody
|
||||
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.eclair.blockchain.bitcoind.rpc.{BitcoinJsonRPCClient, Error, JsonRPCError}
|
||||
import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinJsonRPCClient
|
||||
import org.json4s.DefaultFormats
|
||||
import org.json4s.JsonAST._
|
||||
|
||||
|
@ -16,37 +16,33 @@
|
||||
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||
import akka.stream.ActorMaterializer
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
|
||||
import com.softwaremill.sttp._
|
||||
import com.softwaremill.sttp.json4s._
|
||||
import fr.acinq.bitcoin.{BinaryData, Block}
|
||||
import org.json4s.DefaultFormats
|
||||
import org.json4s.JsonAST.{JInt, JValue}
|
||||
import org.json4s.{DefaultFormats, jackson}
|
||||
import org.json4s.jackson.Serialization
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class BitgoFeeProvider(chainHash: BinaryData)(implicit system: ActorSystem, ec: ExecutionContext) extends FeeProvider {
|
||||
class BitgoFeeProvider(chainHash: BinaryData)(implicit http: SttpBackend[Future, Nothing], ec: ExecutionContext) extends FeeProvider {
|
||||
|
||||
import BitgoFeeProvider._
|
||||
|
||||
implicit val materializer = ActorMaterializer()
|
||||
val httpClient = Http(system)
|
||||
implicit val serialization = jackson.Serialization
|
||||
implicit val formats = DefaultFormats
|
||||
implicit val serialization = Serialization
|
||||
|
||||
val uri = chainHash match {
|
||||
case Block.LivenetGenesisBlock.hash => Uri("https://www.bitgo.com/api/v2/btc/tx/fee")
|
||||
case _ => Uri("https://test.bitgo.com/api/v2/tbtc/tx/fee")
|
||||
case Block.LivenetGenesisBlock.hash => uri"https://www.bitgo.com/api/v2/btc/tx/fee"
|
||||
case _ => uri"https://test.bitgo.com/api/v2/tbtc/tx/fee"
|
||||
}
|
||||
|
||||
override def getFeerates: Future[FeeratesPerKB] =
|
||||
for {
|
||||
httpRes <- httpClient.singleRequest(HttpRequest(uri = uri, method = HttpMethods.GET))
|
||||
json <- Unmarshal(httpRes).to[JValue]
|
||||
feeRanges = parseFeeRanges(json)
|
||||
res <- sttp.get(uri)
|
||||
.response(asJson[JValue])
|
||||
.send()
|
||||
feeRanges = parseFeeRanges(res.unsafeBody)
|
||||
} yield extractFeerates(feeRanges)
|
||||
}
|
||||
|
||||
|
@ -16,34 +16,32 @@
|
||||
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||
import akka.stream.ActorMaterializer
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
|
||||
import com.softwaremill.sttp._
|
||||
import com.softwaremill.sttp.json4s._
|
||||
import org.json4s.DefaultFormats
|
||||
import org.json4s.JsonAST.{JArray, JInt, JValue}
|
||||
import org.json4s.{DefaultFormats, jackson}
|
||||
import org.json4s.jackson.Serialization
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
/**
|
||||
* Created by PM on 16/11/2017.
|
||||
*/
|
||||
class EarnDotComFeeProvider(implicit system: ActorSystem, ec: ExecutionContext) extends FeeProvider {
|
||||
class EarnDotComFeeProvider(implicit http: SttpBackend[Future, Nothing], ec: ExecutionContext) extends FeeProvider {
|
||||
|
||||
import EarnDotComFeeProvider._
|
||||
|
||||
implicit val materializer = ActorMaterializer()
|
||||
val httpClient = Http(system)
|
||||
implicit val serialization = jackson.Serialization
|
||||
implicit val formats = DefaultFormats
|
||||
implicit val serialization = Serialization
|
||||
|
||||
val uri = uri"https://bitcoinfees.earn.com/api/v1/fees/list"
|
||||
|
||||
override def getFeerates: Future[FeeratesPerKB] =
|
||||
for {
|
||||
httpRes <- httpClient.singleRequest(HttpRequest(uri = Uri("https://bitcoinfees.earn.com/api/v1/fees/list"), method = HttpMethods.GET))
|
||||
json <- Unmarshal(httpRes).to[JValue]
|
||||
feeRanges = parseFeeRanges(json)
|
||||
json <- sttp.get(uri)
|
||||
.response(asJson[JValue])
|
||||
.send()
|
||||
feeRanges = parseFeeRanges(json.unsafeBody)
|
||||
} yield extractFeerates(feeRanges)
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ import scala.concurrent.{ExecutionContext, Future}
|
||||
/**
|
||||
* Created by PM on 26/04/2016.
|
||||
*/
|
||||
class TestBitcoinClient()(implicit system: ActorSystem) extends ExtendedBitcoinClient(new BasicBitcoinJsonRPCClient("", "", "", 0)) {
|
||||
class TestBitcoinClient()(implicit system: ActorSystem) extends ExtendedBitcoinClient(new BasicBitcoinJsonRPCClient("", "", "", 0)(http = null)) {
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
|
@ -48,7 +48,6 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe
|
||||
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
startBitcoind()
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import java.util.UUID
|
||||
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
|
||||
import akka.pattern.pipe
|
||||
import akka.testkit.{TestKitBase, TestProbe}
|
||||
import com.softwaremill.sttp.asynchttpclient.future.AsyncHttpClientFutureBackend
|
||||
import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinJsonRPCClient}
|
||||
import fr.acinq.eclair.integration.IntegrationSpec
|
||||
import grizzled.slf4j.Logging
|
||||
@ -35,6 +36,7 @@ trait BitcoindService extends Logging {
|
||||
self: TestKitBase =>
|
||||
|
||||
implicit val system: ActorSystem
|
||||
implicit val sttpBackend = AsyncHttpClientFutureBackend()
|
||||
|
||||
import scala.sys.process._
|
||||
|
||||
|
@ -28,6 +28,7 @@ import fr.acinq.eclair.blockchain.bitcoind.{BitcoinCoreWallet, BitcoindService}
|
||||
import fr.acinq.eclair.blockchain.electrum.ElectrumClient.{BroadcastTransaction, BroadcastTransactionResponse}
|
||||
import grizzled.slf4j.Logging
|
||||
import org.json4s.JsonAST.{JDecimal, JString, JValue}
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.scalatest.{BeforeAndAfterAll, FunSuiteLike}
|
||||
|
||||
import scala.concurrent.Await
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.util.Timeout
|
||||
import com.softwaremill.sttp.asynchttpclient.future.AsyncHttpClientFutureBackend
|
||||
import grizzled.slf4j.Logging
|
||||
import org.json4s.DefaultFormats
|
||||
import org.scalatest.FunSuite
|
||||
@ -70,7 +70,7 @@ class EarnDotComFeeProviderSpec extends FunSuite with Logging {
|
||||
test("make sure API hasn't changed") {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
implicit val system = ActorSystem()
|
||||
implicit val sttpBackend = AsyncHttpClientFutureBackend()
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
val provider = new EarnDotComFeeProvider()
|
||||
logger.info("earn.com livenet fees: " + Await.result(provider.getFeerates, 10 seconds))
|
||||
|
@ -19,7 +19,8 @@ package fr.acinq.eclair.integration
|
||||
import java.io.{File, PrintWriter}
|
||||
import java.util.Properties
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem}
|
||||
import akka.actor.{ActorRef, ActorSystem, Terminated}
|
||||
import akka.pattern.pipe
|
||||
import akka.testkit.{TestKit, TestProbe}
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.typesafe.config.{Config, ConfigFactory}
|
||||
|
@ -19,6 +19,7 @@ package fr.acinq.eclair.router
|
||||
import akka.actor.ActorSystem
|
||||
import akka.pattern.pipe
|
||||
import akka.testkit.TestProbe
|
||||
import com.softwaremill.sttp.asynchttpclient.future.AsyncHttpClientFutureBackend
|
||||
import fr.acinq.bitcoin.Crypto.PrivateKey
|
||||
import fr.acinq.bitcoin.{BinaryData, Block, Satoshi, Script, Transaction}
|
||||
import fr.acinq.eclair.blockchain.ValidateResult
|
||||
@ -44,6 +45,7 @@ class AnnouncementsBatchValidationSpec extends FunSuite {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val sttpBackend = AsyncHttpClientFutureBackend()
|
||||
implicit val extendedBitcoinClient = new ExtendedBitcoinClient(new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = 18332))
|
||||
|
||||
val channels = for (i <- 0 until 50) yield {
|
||||
@ -76,7 +78,7 @@ object AnnouncementsBatchValidationSpec {
|
||||
def generateBlocks(numBlocks: Int)(implicit extendedBitcoinClient: ExtendedBitcoinClient, ec: ExecutionContext) =
|
||||
Await.result(extendedBitcoinClient.rpcClient.invoke("generate", numBlocks), 10 seconds)
|
||||
|
||||
def simulateChannel()(implicit extendedBitcoinClient: ExtendedBitcoinClient, ec: ExecutionContext, system: ActorSystem): SimulatedChannel = {
|
||||
def simulateChannel()(implicit extendedBitcoinClient: ExtendedBitcoinClient, ec: ExecutionContext): SimulatedChannel = {
|
||||
val node1Key = randomKey
|
||||
val node2Key = randomKey
|
||||
val node1BitcoinKey = randomKey
|
||||
|
1
pom.xml
1
pom.xml
@ -66,6 +66,7 @@
|
||||
<scala.version>2.11.11</scala.version>
|
||||
<scala.version.short>2.11</scala.version.short>
|
||||
<akka.version>2.4.20</akka.version>
|
||||
<sttp.version>1.3.9</sttp.version>
|
||||
<bitcoinlib.version>0.9.17</bitcoinlib.version>
|
||||
<guava.version>24.0-android</guava.version>
|
||||
</properties>
|
||||
|
Loading…
Reference in New Issue
Block a user