From e43ddf69410553f00a9c5d2be1ea5006b5f0a04f Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Wed, 7 Nov 2018 19:09:53 +0300 Subject: [PATCH 01/14] added progress --- src/main/resources/application.conf | 7 ++ src/main/scala/mvp2/actors/Anchorer.scala | 102 ++++++++++++++++++++++ src/main/scala/mvp2/actors/Starter.scala | 1 + src/main/scala/mvp2/utils/Settings.scala | 4 + 4 files changed, 114 insertions(+) create mode 100644 src/main/scala/mvp2/actors/Anchorer.scala diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 1ade36b..e118601 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -12,5 +12,12 @@ httpPort = 9151 timeout = 10 } + ethereum { + userAccount = "" + userPassword = "" + receiverAccount = "" + peerRPCAddress = "" + gasPrice = 39062500000 + } } } \ No newline at end of file diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala new file mode 100644 index 0000000..f087bc2 --- /dev/null +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -0,0 +1,102 @@ +package mvp2.actors + +import java.util.concurrent.TimeUnit +import akka.http.scaladsl.Http +import akka.http.scaladsl.model._ +import akka.util.ByteString +import io.circe.Json +import mvp2.utils.EthereumSettings +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, Future} +import scala.util.{Failure, Success} + +class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { + + lazy val gasAmount = 30000 + lazy val ethToTransfer = 0.01 + private var lastEthBlockHash: String = _ + private var unconfirmedQueue: List[UnconfirmedTransaction] = _ + + override def specialBehavior: Receive = { + case blockHash: ByteString => + if (unlockAccount) { + val transactionID: String = sendEthereumTransaction(blockHash) + unconfirmedQueue = UnconfirmedTransaction(blockHash, transactionID, inChain = false) :: unconfirmedQueue + getEthBlockHashWithTransaction(transactionID) match { + case Some(value) => lastEthBlockHash = value + unconfirmedQueue.filter(_.transactionID!=transactionID) + case None => logger.warn("Still not in the block: " + + unconfirmedQueue.filter(_.transactionID==transactionID).head.toString) + } + } + } + + def sendEthereumTransaction(blockHash: ByteString) = { + val transaction: Json = Json.fromFields(List( + ("jsonrpc", Json.fromDoubleOrNull(2.0)), + ("method", Json.fromString("eth_sendTransaction")), + ("params", Json.fromFields(List( + ("from", Json.fromString(ethereumSettings.userAccount)), + ("to", Json.fromString(ethereumSettings.receiverAccount)), + ("value", Json.fromDoubleOrNull(ethToTransfer)) + ("gas", Json.fromString(Integer.toHexString(gasAmount))), + ("gasPrice", Json.fromString(Integer.toHexString(ethereumSettings.gasPrice))), + ("data", Json.fromString(blockHash.toList.map("%02X" format _).mkString.toList.map(_.toInt.toHexString).mkString)) + ))), + ("id", Json.fromInt(1)) + )) + + "tx_id" + } + + def unlockAccount: Boolean = { + val jsonToUnlock = Json.fromFields(List ( + ("jsonrpc", Json.fromDoubleOrNull(2.0)), + ("method", Json.fromString("personal_unlockAccount")), + ("params", Json.fromValues(List( + Json.fromString(ethereumSettings.userAccount), + Json.fromString(ethereumSettings.userPassword), + Json.fromInt(600) + ))) + ("id", Json.fromInt(67)) + )) + val unlockResponseFuture: Future[HttpResponse] = Http().singleRequest( + HttpRequest( + HttpMethods.POST, ethereumSettings.peerRPCAddress, + entity=HttpEntity(MediaTypes.`application/json`, jsonToUnlock.toString) + )) + unlockResponseFuture.onComplete { + case Success(res) => + } + } + + def getEthBlockHashWithTransaction(transactionID: String): Option[String] = { + val requestBody = Json.fromFields(List ( + ("jsonrpc", Json.fromDoubleOrNull(2.0)), + ("method", Json.fromString("eth_getTransactionReceipt")), + ("params", Json.fromValues(List(Json.fromString(transactionID)))) + ("id", Json.fromInt(1)) + )) + Some("block_hash") + } + + def getLastEthBlockHash: String = lastEthBlockHash + + def sendRequestReceiveResponse(json: Json) = { + val responseFuture: Future[HttpResponse] = Http().singleRequest( + HttpRequest( + HttpMethods.POST, ethereumSettings.peerRPCAddress, + entity=HttpEntity(MediaTypes.`application/json`, json.toString) + )) + responseFuture.onComplete { + case Success(response) => response.status match { + case StatusCodes.OK if (response.entity.contentType == ContentTypes.`application/json`) => + } + case Failure(e) => logger.error(e.toString) + } + Await.result(responseFuture, Duration.apply(30, TimeUnit.SECONDS)) + } + +} + +case class UnconfirmedTransaction(BlockHash: ByteString, transactionID: String, inChain:Boolean) diff --git a/src/main/scala/mvp2/actors/Starter.scala b/src/main/scala/mvp2/actors/Starter.scala index ca00b8e..cdfc536 100644 --- a/src/main/scala/mvp2/actors/Starter.scala +++ b/src/main/scala/mvp2/actors/Starter.scala @@ -32,5 +32,6 @@ class Starter extends CommonActor { context.actorOf(Props(classOf[ConsoleActor], settings), "cliActor") context.actorOf(Props(classOf[Informator], settings), "informator") context.actorOf(Props(classOf[Zombie]), "zombie") + context.actorOf(Props(classOf[Anchorer], settings.ethereumSettings, "anchorer")) } } \ No newline at end of file diff --git a/src/main/scala/mvp2/utils/Settings.scala b/src/main/scala/mvp2/utils/Settings.scala index 4e8da76..7491997 100644 --- a/src/main/scala/mvp2/utils/Settings.scala +++ b/src/main/scala/mvp2/utils/Settings.scala @@ -7,6 +7,7 @@ case class Settings(port: Int, blockPeriod: Long, biasForBlockPeriod: Long, apiSettings: ApiSettings, + ethereumSettings: EthereumSettings, influx: Option[InfluxSettings], testingSettings: Option[TestingSettings] ) @@ -17,4 +18,7 @@ case class ApiSettings(httpHost: String, httpPort: Int, timeout: Int) case class InfluxSettings(host: String, port: Int, login: String, password: String) +case class EthereumSettings(userAccount: String, userPassword: String, receiverAccount:String, + peerRPCAddress: String, gasPrice: Int) + case class TestingSettings(pingPong: Boolean) \ No newline at end of file From d0614a112117755ebf505f35ae89cfce5588540f Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 8 Nov 2018 10:25:13 +0300 Subject: [PATCH 02/14] added tx route --- src/main/scala/mvp2/actors/Informator.scala | 12 ++++++++-- .../scala/mvp2/http/TransactionRoute.scala | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/mvp2/http/TransactionRoute.scala diff --git a/src/main/scala/mvp2/actors/Informator.scala b/src/main/scala/mvp2/actors/Informator.scala index bc96a95..f728922 100644 --- a/src/main/scala/mvp2/actors/Informator.scala +++ b/src/main/scala/mvp2/actors/Informator.scala @@ -2,9 +2,10 @@ package mvp2.actors import akka.actor.ActorRefFactory import mvp2.messages.Get -import mvp2.http.ApiRoute +import mvp2.http.{ApiRoute, TransactionRoute} import mvp2.messages.CurrentBlockchainInfo import akka.http.scaladsl.Http +import akka.http.scaladsl.server.Route import mvp2.MVP2._ import mvp2.utils.Settings @@ -26,7 +27,14 @@ class Informator(settings: Settings) extends CommonActor { object Informator { + def routesCompose(settings: Settings, context: ActorRefFactory): Seq[Route] = { + val routes: Seq[Route] = Seq(ApiRoute(settings, context).apiInfo, TransactionRoute(settings, context).route) + val result = routes.reduce(x => x ~ _) + } + def start(settings: Settings, context: ActorRefFactory): Unit = Http().bindAndHandle( - ApiRoute(settings, context).apiInfo, settings.apiSettings.httpHost, settings.apiSettings.httpPort + ApiRoute(settings, context).apiInfo ~ TransactionRoute(settings, context).route, + settings.apiSettings.httpHost, + settings.apiSettings.httpPort ) } \ No newline at end of file diff --git a/src/main/scala/mvp2/http/TransactionRoute.scala b/src/main/scala/mvp2/http/TransactionRoute.scala new file mode 100644 index 0000000..ff840d7 --- /dev/null +++ b/src/main/scala/mvp2/http/TransactionRoute.scala @@ -0,0 +1,24 @@ +package mvp2.http + +import akka.actor.{ActorRefFactory, ActorSelection} +import akka.http.scaladsl.server.Route +import mvp2.utils.Settings +import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.server.Directives._ +import mvp2.data.Transaction +import mvp2.MVP2.system + +case class TransactionRoute(settings: Settings, implicit val context: ActorRefFactory) { + + val publisher: ActorSelection = system.actorSelection("user/starter/blockchainer/publisher") + + val route: Route = { + path("getTxs")(entity(as[List[Transaction]]) { + txs => complete { + txs.foreach(tx => publisher ! tx) + StatusCodes.OK + } + }) + } + +} \ No newline at end of file From 28f8dd1a3073e3d87ba0f34d4ef490f3b01d2656 Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 8 Nov 2018 10:27:47 +0300 Subject: [PATCH 03/14] fixed --- src/main/scala/mvp2/actors/Informator.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/mvp2/actors/Informator.scala b/src/main/scala/mvp2/actors/Informator.scala index f728922..f944590 100644 --- a/src/main/scala/mvp2/actors/Informator.scala +++ b/src/main/scala/mvp2/actors/Informator.scala @@ -5,6 +5,7 @@ import mvp2.messages.Get import mvp2.http.{ApiRoute, TransactionRoute} import mvp2.messages.CurrentBlockchainInfo import akka.http.scaladsl.Http +import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route import mvp2.MVP2._ import mvp2.utils.Settings @@ -27,13 +28,16 @@ class Informator(settings: Settings) extends CommonActor { object Informator { - def routesCompose(settings: Settings, context: ActorRefFactory): Seq[Route] = { - val routes: Seq[Route] = Seq(ApiRoute(settings, context).apiInfo, TransactionRoute(settings, context).route) - val result = routes.reduce(x => x ~ _) + def routesCompose(settings: Settings, context: ActorRefFactory): Route = { + val routes: Seq[Route] = Seq( + ApiRoute(settings, context).apiInfo, + TransactionRoute(settings, context).route + ) + routes.reduce(_ ~ _) } def start(settings: Settings, context: ActorRefFactory): Unit = Http().bindAndHandle( - ApiRoute(settings, context).apiInfo ~ TransactionRoute(settings, context).route, + routesCompose(settings, context), settings.apiSettings.httpHost, settings.apiSettings.httpPort ) From c82983abfdbf6594840d1ea08b167ae1504d0103 Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 8 Nov 2018 15:27:28 +0300 Subject: [PATCH 04/14] added post route for a list of transactions --- src/main/scala/mvp2/actors/Informator.scala | 14 +----- src/main/scala/mvp2/actors/Publisher.scala | 8 ++-- src/main/scala/mvp2/actors/Starter.scala | 2 +- .../http/{ApiRoute.scala => Routes.scala} | 45 ++++++++++++++----- .../scala/mvp2/http/TransactionRoute.scala | 24 ---------- 5 files changed, 41 insertions(+), 52 deletions(-) rename src/main/scala/mvp2/http/{ApiRoute.scala => Routes.scala} (52%) delete mode 100644 src/main/scala/mvp2/http/TransactionRoute.scala diff --git a/src/main/scala/mvp2/actors/Informator.scala b/src/main/scala/mvp2/actors/Informator.scala index f944590..f30ec5b 100644 --- a/src/main/scala/mvp2/actors/Informator.scala +++ b/src/main/scala/mvp2/actors/Informator.scala @@ -2,11 +2,9 @@ package mvp2.actors import akka.actor.ActorRefFactory import mvp2.messages.Get -import mvp2.http.{ApiRoute, TransactionRoute} +import mvp2.http.Routes import mvp2.messages.CurrentBlockchainInfo import akka.http.scaladsl.Http -import akka.http.scaladsl.server.Directives._ -import akka.http.scaladsl.server.Route import mvp2.MVP2._ import mvp2.utils.Settings @@ -28,16 +26,8 @@ class Informator(settings: Settings) extends CommonActor { object Informator { - def routesCompose(settings: Settings, context: ActorRefFactory): Route = { - val routes: Seq[Route] = Seq( - ApiRoute(settings, context).apiInfo, - TransactionRoute(settings, context).route - ) - routes.reduce(_ ~ _) - } - def start(settings: Settings, context: ActorRefFactory): Unit = Http().bindAndHandle( - routesCompose(settings, context), + Routes(settings, context).route, settings.apiSettings.httpHost, settings.apiSettings.httpPort ) diff --git a/src/main/scala/mvp2/actors/Publisher.scala b/src/main/scala/mvp2/actors/Publisher.scala index e8998d6..aacf175 100644 --- a/src/main/scala/mvp2/actors/Publisher.scala +++ b/src/main/scala/mvp2/actors/Publisher.scala @@ -15,14 +15,14 @@ class Publisher(settings: Settings) extends CommonActor { override def specialBehavior: Receive = { case transaction: Transaction => - logger.info(s"Publisher received tx: $transaction and put it to the mempool.") + println(s"Publisher received tx: $transaction and put it to the mempool.") mempool = transaction :: mempool case keyBlock: KeyBlock => logger.info(s"Publisher received new lastKeyBlock with height ${keyBlock.height}.") lastKeyBlock = keyBlock case Get => val newBlock: KeyBlock = createKeyBlock - println(s"Publisher got new request and published block with height ${newBlock.height}.") + //println(s"Publisher got new request and published block with height ${newBlock.height}.") context.parent ! newBlock networker ! newBlock } @@ -31,8 +31,8 @@ class Publisher(settings: Settings) extends CommonActor { val keyBlock: KeyBlock = KeyBlock(lastKeyBlock.height + 1, System.currentTimeMillis, lastKeyBlock.currentBlockHash, mempool) //logger.info(s"${mempool.size} transactions in the mempool.") - println(s"New keyBlock with height ${keyBlock.height} is published by local publisher. " + - s"${keyBlock.transactions.size} transactions inside.") + //println(s"New keyBlock with height ${keyBlock.height} is published by local publisher. " + + // s"${keyBlock.transactions.size} transactions inside.") mempool = List.empty //logger.info(s"${mempool.size} transactions in the mempool.") keyBlock diff --git a/src/main/scala/mvp2/actors/Starter.scala b/src/main/scala/mvp2/actors/Starter.scala index bd047b8..1312584 100644 --- a/src/main/scala/mvp2/actors/Starter.scala +++ b/src/main/scala/mvp2/actors/Starter.scala @@ -30,8 +30,8 @@ class Starter extends CommonActor { context.actorOf(Props(classOf[InfluxActor], influxSettings), name = "influxActor") ) context.actorOf(Props(classOf[ConsoleActor], settings), "cliActor") - context.actorOf(Props(classOf[Informator], settings), "informator") context.actorOf(Props(classOf[Zombie]), "zombie") */ + context.actorOf(Props(classOf[Informator], settings), "informator") } } \ No newline at end of file diff --git a/src/main/scala/mvp2/http/ApiRoute.scala b/src/main/scala/mvp2/http/Routes.scala similarity index 52% rename from src/main/scala/mvp2/http/ApiRoute.scala rename to src/main/scala/mvp2/http/Routes.scala index d43344f..5546c30 100644 --- a/src/main/scala/mvp2/http/ApiRoute.scala +++ b/src/main/scala/mvp2/http/Routes.scala @@ -1,34 +1,57 @@ package mvp2.http import akka.http.scaladsl.server.Directives.complete -import akka.actor.ActorRefFactory +import akka.actor.ActorSelection import akka.http.scaladsl.model.{ContentTypes, HttpEntity} -import akka.http.scaladsl.server.Directives._ +import mvp2.MVP2.system +import mvp2.data.Transaction +import mvp2.messages.{CurrentBlockchainInfo, Get} +import mvp2.utils.Settings +import akka.actor.ActorRefFactory +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Route -import akka.pattern.ask -import akka.util.Timeout import io.circe.Json -import io.circe.syntax._ +import scala.concurrent.Future import io.circe.generic.auto._ +import io.circe.syntax._ +import scala.concurrent.ExecutionContextExecutor import scala.concurrent.duration._ -import scala.concurrent.{ExecutionContextExecutor, Future} +import scala.language.postfixOps +import akka.http.scaladsl.server.Directives._ +import akka.pattern.ask +import akka.stream.ActorMaterializer +import akka.util.Timeout +import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport import mvp2.utils.EncodingUtils._ -import mvp2.messages.{CurrentBlockchainInfo, Get} -import mvp2.utils.Settings -case class ApiRoute(settings: Settings, implicit val context: ActorRefFactory) { +case class Routes(settings: Settings, implicit val context: ActorRefFactory) extends FailFastCirceSupport { implicit val ec: ExecutionContextExecutor = context.dispatcher implicit val timeout: Timeout = Timeout(settings.apiSettings.timeout.second) + implicit val materializer: ActorMaterializer = ActorMaterializer() + + val route: Route = getTxs ~ apiInfo def apiInfoVal: Future[CurrentBlockchainInfo] = (context.actorSelection("/user/starter/informator") ? Get).mapTo[CurrentBlockchainInfo] - def toJsonResponse(fJson: Future[Json]): Route = onSuccess(fJson) (resp => + def toJsonResponse(fJson: Future[Json]): Route = onSuccess(fJson)(resp => complete(HttpEntity(ContentTypes.`application/json`, resp.spaces2)) ) - val apiInfo: Route = pathPrefix("info")( + def apiInfo: Route = pathPrefix("info")( toJsonResponse(apiInfoVal.map(_.asJson)) ) + + val publisher: ActorSelection = system.actorSelection("user/starter/blockchainer/publisher") + + def getTxs: Route = path("sendTx") { + post(entity(as[List[Transaction]]) { + txs => + complete { + txs.foreach(tx => publisher ! tx) + StatusCodes.OK + } + }) + } } \ No newline at end of file diff --git a/src/main/scala/mvp2/http/TransactionRoute.scala b/src/main/scala/mvp2/http/TransactionRoute.scala deleted file mode 100644 index ff840d7..0000000 --- a/src/main/scala/mvp2/http/TransactionRoute.scala +++ /dev/null @@ -1,24 +0,0 @@ -package mvp2.http - -import akka.actor.{ActorRefFactory, ActorSelection} -import akka.http.scaladsl.server.Route -import mvp2.utils.Settings -import akka.http.scaladsl.model.StatusCodes -import akka.http.scaladsl.server.Directives._ -import mvp2.data.Transaction -import mvp2.MVP2.system - -case class TransactionRoute(settings: Settings, implicit val context: ActorRefFactory) { - - val publisher: ActorSelection = system.actorSelection("user/starter/blockchainer/publisher") - - val route: Route = { - path("getTxs")(entity(as[List[Transaction]]) { - txs => complete { - txs.foreach(tx => publisher ! tx) - StatusCodes.OK - } - }) - } - -} \ No newline at end of file From 4630d693e32c158fbf7dad4bffb1f0f14a4319af Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 8 Nov 2018 15:32:01 +0300 Subject: [PATCH 05/14] cleanup code --- src/main/scala/mvp2/actors/Publisher.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/mvp2/actors/Publisher.scala b/src/main/scala/mvp2/actors/Publisher.scala index aacf175..e8998d6 100644 --- a/src/main/scala/mvp2/actors/Publisher.scala +++ b/src/main/scala/mvp2/actors/Publisher.scala @@ -15,14 +15,14 @@ class Publisher(settings: Settings) extends CommonActor { override def specialBehavior: Receive = { case transaction: Transaction => - println(s"Publisher received tx: $transaction and put it to the mempool.") + logger.info(s"Publisher received tx: $transaction and put it to the mempool.") mempool = transaction :: mempool case keyBlock: KeyBlock => logger.info(s"Publisher received new lastKeyBlock with height ${keyBlock.height}.") lastKeyBlock = keyBlock case Get => val newBlock: KeyBlock = createKeyBlock - //println(s"Publisher got new request and published block with height ${newBlock.height}.") + println(s"Publisher got new request and published block with height ${newBlock.height}.") context.parent ! newBlock networker ! newBlock } @@ -31,8 +31,8 @@ class Publisher(settings: Settings) extends CommonActor { val keyBlock: KeyBlock = KeyBlock(lastKeyBlock.height + 1, System.currentTimeMillis, lastKeyBlock.currentBlockHash, mempool) //logger.info(s"${mempool.size} transactions in the mempool.") - //println(s"New keyBlock with height ${keyBlock.height} is published by local publisher. " + - // s"${keyBlock.transactions.size} transactions inside.") + println(s"New keyBlock with height ${keyBlock.height} is published by local publisher. " + + s"${keyBlock.transactions.size} transactions inside.") mempool = List.empty //logger.info(s"${mempool.size} transactions in the mempool.") keyBlock From 663281ac818694b58b6df6a4c073f9236444ce23 Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Thu, 8 Nov 2018 15:55:30 +0300 Subject: [PATCH 06/14] before merging routes --- src/main/scala/mvp2/actors/Anchorer.scala | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index f087bc2..3ccd2eb 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -3,6 +3,7 @@ package mvp2.actors import java.util.concurrent.TimeUnit import akka.http.scaladsl.Http import akka.http.scaladsl.model._ +import akka.http.scaladsl.unmarshalling.Unmarshal import akka.util.ByteString import io.circe.Json import mvp2.utils.EthereumSettings @@ -38,7 +39,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { ("params", Json.fromFields(List( ("from", Json.fromString(ethereumSettings.userAccount)), ("to", Json.fromString(ethereumSettings.receiverAccount)), - ("value", Json.fromDoubleOrNull(ethToTransfer)) + ("value", Json.fromDoubleOrNull(ethToTransfer)), ("gas", Json.fromString(Integer.toHexString(gasAmount))), ("gasPrice", Json.fromString(Integer.toHexString(ethereumSettings.gasPrice))), ("data", Json.fromString(blockHash.toList.map("%02X" format _).mkString.toList.map(_.toInt.toHexString).mkString)) @@ -60,14 +61,14 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { ))) ("id", Json.fromInt(67)) )) - val unlockResponseFuture: Future[HttpResponse] = Http().singleRequest( - HttpRequest( - HttpMethods.POST, ethereumSettings.peerRPCAddress, - entity=HttpEntity(MediaTypes.`application/json`, jsonToUnlock.toString) - )) - unlockResponseFuture.onComplete { - case Success(res) => - } +// val unlockResponseFuture: Future[HttpResponse] = Http().singleRequest( +// HttpRequest( +// HttpMethods.POST, ethereumSettings.peerRPCAddress, +// entity=HttpEntity(MediaTypes.`application/json`, jsonToUnlock.toString) +// )) +// unlockResponseFuture.onComplete { +// case Success(res) => +// } } def getEthBlockHashWithTransaction(transactionID: String): Option[String] = { @@ -91,12 +92,12 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { responseFuture.onComplete { case Success(response) => response.status match { case StatusCodes.OK if (response.entity.contentType == ContentTypes.`application/json`) => + Unmarshal(response.entity).to[String].map() } case Failure(e) => logger.error(e.toString) } Await.result(responseFuture, Duration.apply(30, TimeUnit.SECONDS)) } - } case class UnconfirmedTransaction(BlockHash: ByteString, transactionID: String, inChain:Boolean) From 10c0246dbec81df354c7625b4db228ee590c68f2 Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Fri, 9 Nov 2018 13:39:04 +0300 Subject: [PATCH 07/14] added service, refactored logic --- build.sbt | 1 + src/main/scala/mvp2/actors/Anchorer.scala | 94 +++++++++---------- .../scala/mvp2/http/EthereumService.scala | 44 +++++++++ src/main/scala/mvp2/http/Routes.scala | 3 +- .../scala/mvp2/utils/EthRequestType.scala | 6 ++ 5 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 src/main/scala/mvp2/http/EthereumService.scala create mode 100644 src/main/scala/mvp2/utils/EthRequestType.scala diff --git a/build.sbt b/build.sbt index 101b442..31da6f8 100644 --- a/build.sbt +++ b/build.sbt @@ -14,6 +14,7 @@ libraryDependencies ++= Seq( "org.fusesource.leveldbjni" % "leveldbjni-all" % "1.8", "org.iq80.leveldb" % "leveldb" % "0.7", "io.circe" %% "circe-generic" % "0.9.3", + "io.circe" %% "circe-parser" % "0.9.3", "javax.xml.bind" % "jaxb-api" % "2.3.0", "com.iheart" %% "ficus" % "1.4.2", "org.slf4j" % "slf4j-api" % "1.7.25", diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index 3ccd2eb..c9f0918 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -1,15 +1,11 @@ package mvp2.actors -import java.util.concurrent.TimeUnit -import akka.http.scaladsl.Http -import akka.http.scaladsl.model._ -import akka.http.scaladsl.unmarshalling.Unmarshal +import java.util.UUID.randomUUID import akka.util.ByteString +import com.google.common.io.BaseEncoding import io.circe.Json -import mvp2.utils.EthereumSettings -import scala.concurrent.duration.Duration -import scala.concurrent.{Await, Future} -import scala.util.{Failure, Success} +import mvp2.http.{EthResponse, EthereumService} +import mvp2.utils.{EthRequestType, EthereumSettings} class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { @@ -19,21 +15,29 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { private var unconfirmedQueue: List[UnconfirmedTransaction] = _ override def specialBehavior: Receive = { + case blockHash: ByteString => - if (unlockAccount) { - val transactionID: String = sendEthereumTransaction(blockHash) - unconfirmedQueue = UnconfirmedTransaction(blockHash, transactionID, inChain = false) :: unconfirmedQueue - getEthBlockHashWithTransaction(transactionID) match { - case Some(value) => lastEthBlockHash = value - unconfirmedQueue.filter(_.transactionID!=transactionID) - case None => logger.warn("Still not in the block: " + - unconfirmedQueue.filter(_.transactionID==transactionID).head.toString) - } + unconfirmedQueue = UnconfirmedTransaction(randomUUID().toString, blockHash, "", isUnlocked=false) :: unconfirmedQueue + sendUnlockAccount(unconfirmedQueue.head) + case response: EthResponse => response.rtype match { + case EthRequestType.UNLOCKACC => if (getUnlockResult(response.responseBody)) + unconfirmedQueue = unconfirmedQueue.filter(_.innerId==response.innerId).head.copy(isUnlocked = true) :: + unconfirmedQueue.filter(_.innerId!=response.innerId) + sendEthereumTransaction(unconfirmedQueue.head) + case EthRequestType.SENDTX => + unconfirmedQueue = unconfirmedQueue.filter(_.innerId==response.innerId) + .head.copy(transactionEthID = getTransactionId(response.responseBody)) :: + unconfirmedQueue.filter(_.innerId!=response.innerId) + sendTransactionReceiptRequest(unconfirmedQueue.head) + case EthRequestType.GETRESULT => if (getTransactionReceipt(response.responseBody)._1){ + lastEthBlockHash = getTransactionReceipt(response.responseBody)._2 + unconfirmedQueue = unconfirmedQueue.filter(_.innerId!=response.innerId) } + } } - def sendEthereumTransaction(blockHash: ByteString) = { - val transaction: Json = Json.fromFields(List( + def sendEthereumTransaction(transaction: UnconfirmedTransaction): Unit = { + val transactionJson: Json = Json.fromFields(List( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("eth_sendTransaction")), ("params", Json.fromFields(List( @@ -42,15 +46,15 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { ("value", Json.fromDoubleOrNull(ethToTransfer)), ("gas", Json.fromString(Integer.toHexString(gasAmount))), ("gasPrice", Json.fromString(Integer.toHexString(ethereumSettings.gasPrice))), - ("data", Json.fromString(blockHash.toList.map("%02X" format _).mkString.toList.map(_.toInt.toHexString).mkString)) + ("data", Json.fromString(encode2Base16(transaction.blockHash))) ))), ("id", Json.fromInt(1)) )) - - "tx_id" + EthereumService + .sendRequestToEthereum(transaction.innerId, transactionJson, ethereumSettings.peerRPCAddress, EthRequestType.SENDTX) } - def unlockAccount: Boolean = { + def sendUnlockAccount(transaction: UnconfirmedTransaction): Unit = { val jsonToUnlock = Json.fromFields(List ( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("personal_unlockAccount")), @@ -61,43 +65,33 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { ))) ("id", Json.fromInt(67)) )) -// val unlockResponseFuture: Future[HttpResponse] = Http().singleRequest( -// HttpRequest( -// HttpMethods.POST, ethereumSettings.peerRPCAddress, -// entity=HttpEntity(MediaTypes.`application/json`, jsonToUnlock.toString) -// )) -// unlockResponseFuture.onComplete { -// case Success(res) => -// } + EthereumService + .sendRequestToEthereum(transaction.innerId, jsonToUnlock, ethereumSettings.peerRPCAddress, EthRequestType.UNLOCKACC) } - def getEthBlockHashWithTransaction(transactionID: String): Option[String] = { + def sendTransactionReceiptRequest(transaction: UnconfirmedTransaction): Unit = { val requestBody = Json.fromFields(List ( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("eth_getTransactionReceipt")), - ("params", Json.fromValues(List(Json.fromString(transactionID)))) + ("params", Json.fromValues(List(Json.fromString(transaction.transactionEthID)))) ("id", Json.fromInt(1)) )) - Some("block_hash") + EthereumService + .sendRequestToEthereum(transaction.innerId, requestBody, ethereumSettings.peerRPCAddress, EthRequestType.GETRESULT) } + def getUnlockResult(json: Json): Boolean = json.hcursor.downField("result").as[Boolean].getOrElse(false) + + def getTransactionReceipt(json: Json): (Boolean, String) = + (json.hcursor.downField("status").as[String].getOrElse("")=="0x1", json.hcursor.as[String].getOrElse("")) + + def getTransactionId(json: Json): String = json.hcursor.downField("result").as[String].getOrElse("") + def getLastEthBlockHash: String = lastEthBlockHash - def sendRequestReceiveResponse(json: Json) = { - val responseFuture: Future[HttpResponse] = Http().singleRequest( - HttpRequest( - HttpMethods.POST, ethereumSettings.peerRPCAddress, - entity=HttpEntity(MediaTypes.`application/json`, json.toString) - )) - responseFuture.onComplete { - case Success(response) => response.status match { - case StatusCodes.OK if (response.entity.contentType == ContentTypes.`application/json`) => - Unmarshal(response.entity).to[String].map() - } - case Failure(e) => logger.error(e.toString) - } - Await.result(responseFuture, Duration.apply(30, TimeUnit.SECONDS)) - } + def encode2Base16(bytes: ByteString): String = "0x" + BaseEncoding.base16().encode(bytes.toArray) + } -case class UnconfirmedTransaction(BlockHash: ByteString, transactionID: String, inChain:Boolean) +case class UnconfirmedTransaction(innerId: String, blockHash: ByteString, + transactionEthID: String, isUnlocked: Boolean) diff --git a/src/main/scala/mvp2/http/EthereumService.scala b/src/main/scala/mvp2/http/EthereumService.scala new file mode 100644 index 0000000..1cb5b48 --- /dev/null +++ b/src/main/scala/mvp2/http/EthereumService.scala @@ -0,0 +1,44 @@ +package mvp2.http + +import java.util.concurrent.TimeUnit +import akka.actor.ActorSelection +import akka.http.scaladsl.Http +import akka.http.scaladsl.model._ +import akka.http.scaladsl.unmarshalling.Unmarshal +import io.circe.Json +import io.circe.parser.parse +import mvp2.MVP2.system +import mvp2.utils.EthRequestType.EthRequestType +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, Future} +import scala.util.{Failure, Success} + +object EthereumService { + + val anchorer: ActorSelection = system.actorSelection("user/starter/anchorer") + + def sendRequestToEthereum(innerId: String, requestBody: Json, peerRPCAddress: String, requestType: EthRequestType): Unit = { + val responseFuture: Future[HttpResponse] = Http().singleRequest( + HttpRequest( + method = HttpMethods.POST, + uri = peerRPCAddress, + entity = HttpEntity(ContentTypes.`application/json`, requestBody.toString) + )) + responseFuture.onComplete{ + case Success(response) => response.status match { + case StatusCodes.OK if response.entity.contentType == ContentTypes.`application/json` => + Unmarshal(response.entity).to[String].onComplete { + case Success(s) => parse(s) match { + case Right(json) => anchorer ! EthResponse(innerId, requestType, json) + case Left(_) => ??? + } + case Failure(e) => ??? + } + } + case Failure(e) => ??? + } + Await.result(responseFuture, Duration.apply(4, TimeUnit.SECONDS)) + } +} + +case class EthResponse(innerId: String, rtype: EthRequestType, responseBody: Json) diff --git a/src/main/scala/mvp2/http/Routes.scala b/src/main/scala/mvp2/http/Routes.scala index 5546c30..3652f78 100644 --- a/src/main/scala/mvp2/http/Routes.scala +++ b/src/main/scala/mvp2/http/Routes.scala @@ -2,13 +2,12 @@ package mvp2.http import akka.http.scaladsl.server.Directives.complete import akka.actor.ActorSelection -import akka.http.scaladsl.model.{ContentTypes, HttpEntity} +import akka.http.scaladsl.model.{ContentTypes, HttpEntity, StatusCodes} import mvp2.MVP2.system import mvp2.data.Transaction import mvp2.messages.{CurrentBlockchainInfo, Get} import mvp2.utils.Settings import akka.actor.ActorRefFactory -import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Route import io.circe.Json import scala.concurrent.Future diff --git a/src/main/scala/mvp2/utils/EthRequestType.scala b/src/main/scala/mvp2/utils/EthRequestType.scala new file mode 100644 index 0000000..14b3fe7 --- /dev/null +++ b/src/main/scala/mvp2/utils/EthRequestType.scala @@ -0,0 +1,6 @@ +package mvp2.utils + +object EthRequestType extends Enumeration { + type EthRequestType = Value + val UNLOCKACC, SENDTX, GETRESULT = Value +} From 1771bda71ebd5815e92871d5c0f4ed4918b43905 Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Fri, 9 Nov 2018 14:06:46 +0300 Subject: [PATCH 08/14] implicits fix --- src/main/scala/mvp2/actors/Anchorer.scala | 5 ++--- src/main/scala/mvp2/http/EthereumService.scala | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index c9f0918..b8ec8c9 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -15,7 +15,6 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { private var unconfirmedQueue: List[UnconfirmedTransaction] = _ override def specialBehavior: Receive = { - case blockHash: ByteString => unconfirmedQueue = UnconfirmedTransaction(randomUUID().toString, blockHash, "", isUnlocked=false) :: unconfirmedQueue sendUnlockAccount(unconfirmedQueue.head) @@ -62,7 +61,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { Json.fromString(ethereumSettings.userAccount), Json.fromString(ethereumSettings.userPassword), Json.fromInt(600) - ))) + ))), ("id", Json.fromInt(67)) )) EthereumService @@ -73,7 +72,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { val requestBody = Json.fromFields(List ( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("eth_getTransactionReceipt")), - ("params", Json.fromValues(List(Json.fromString(transaction.transactionEthID)))) + ("params", Json.fromValues(List(Json.fromString(transaction.transactionEthID)))), ("id", Json.fromInt(1)) )) EthereumService diff --git a/src/main/scala/mvp2/http/EthereumService.scala b/src/main/scala/mvp2/http/EthereumService.scala index 1cb5b48..6047d43 100644 --- a/src/main/scala/mvp2/http/EthereumService.scala +++ b/src/main/scala/mvp2/http/EthereumService.scala @@ -5,16 +5,18 @@ import akka.actor.ActorSelection import akka.http.scaladsl.Http import akka.http.scaladsl.model._ import akka.http.scaladsl.unmarshalling.Unmarshal +import akka.stream.ActorMaterializer import io.circe.Json import io.circe.parser.parse import mvp2.MVP2.system import mvp2.utils.EthRequestType.EthRequestType +import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration -import scala.concurrent.{Await, Future} +import scala.concurrent.{Await, ExecutionContextExecutor, Future} import scala.util.{Failure, Success} object EthereumService { - + implicit val materializer: ActorMaterializer = ActorMaterializer() val anchorer: ActorSelection = system.actorSelection("user/starter/anchorer") def sendRequestToEthereum(innerId: String, requestBody: Json, peerRPCAddress: String, requestType: EthRequestType): Unit = { From b2f6543600f35844e635c204a44a402dbb5800fb Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Fri, 9 Nov 2018 18:37:51 +0300 Subject: [PATCH 09/14] added logging --- src/main/scala/mvp2/http/EthereumService.scala | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/scala/mvp2/http/EthereumService.scala b/src/main/scala/mvp2/http/EthereumService.scala index 6047d43..f7f2d4f 100644 --- a/src/main/scala/mvp2/http/EthereumService.scala +++ b/src/main/scala/mvp2/http/EthereumService.scala @@ -6,16 +6,17 @@ import akka.http.scaladsl.Http import akka.http.scaladsl.model._ import akka.http.scaladsl.unmarshalling.Unmarshal import akka.stream.ActorMaterializer +import com.typesafe.scalalogging.StrictLogging import io.circe.Json import io.circe.parser.parse import mvp2.MVP2.system import mvp2.utils.EthRequestType.EthRequestType import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration -import scala.concurrent.{Await, ExecutionContextExecutor, Future} +import scala.concurrent.{Await, Future} import scala.util.{Failure, Success} -object EthereumService { +object EthereumService extends StrictLogging { implicit val materializer: ActorMaterializer = ActorMaterializer() val anchorer: ActorSelection = system.actorSelection("user/starter/anchorer") @@ -32,14 +33,14 @@ object EthereumService { Unmarshal(response.entity).to[String].onComplete { case Success(s) => parse(s) match { case Right(json) => anchorer ! EthResponse(innerId, requestType, json) - case Left(_) => ??? + case Left(e) => logger.error("failed to parse json response from ethereum:" + e.getMessage) } - case Failure(e) => ??? + case Failure(e) => logger.error("failed to Unmarshal response from ethereum:" + e.getMessage) } } - case Failure(e) => ??? + case Failure(e) => logger.error("failed to get response from ethereum:" + e.getMessage) } - Await.result(responseFuture, Duration.apply(4, TimeUnit.SECONDS)) + Await.result(responseFuture, Duration.apply(5, TimeUnit.SECONDS)) } } From 8256fcaa2947644b317da2bea722881c6dc17a4e Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Fri, 9 Nov 2018 18:51:18 +0300 Subject: [PATCH 10/14] small fix --- src/main/scala/mvp2/actors/Anchorer.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index b8ec8c9..aaabb36 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -82,7 +82,8 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { def getUnlockResult(json: Json): Boolean = json.hcursor.downField("result").as[Boolean].getOrElse(false) def getTransactionReceipt(json: Json): (Boolean, String) = - (json.hcursor.downField("status").as[String].getOrElse("")=="0x1", json.hcursor.as[String].getOrElse("")) + (json.hcursor.downField("status").as[String].getOrElse("")=="0x1", + json.hcursor.downField("blockHash").as[String].getOrElse("")) def getTransactionId(json: Json): String = json.hcursor.downField("result").as[String].getOrElse("") @@ -93,4 +94,4 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { } case class UnconfirmedTransaction(innerId: String, blockHash: ByteString, - transactionEthID: String, isUnlocked: Boolean) + transactionEthID: String, isUnlocked: Boolean) \ No newline at end of file From 42b44548e8c6178431f4b4f61f0c6187da8e1f2f Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Mon, 12 Nov 2018 11:10:18 +0300 Subject: [PATCH 11/14] added scheduled retrying --- src/main/scala/mvp2/actors/Anchorer.scala | 34 +++++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index aaabb36..7f082ca 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -6,6 +6,7 @@ import com.google.common.io.BaseEncoding import io.circe.Json import mvp2.http.{EthResponse, EthereumService} import mvp2.utils.{EthRequestType, EthereumSettings} +import scala.concurrent.duration._ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { @@ -16,25 +17,34 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { override def specialBehavior: Receive = { case blockHash: ByteString => - unconfirmedQueue = UnconfirmedTransaction(randomUUID().toString, blockHash, "", isUnlocked=false) :: unconfirmedQueue + unconfirmedQueue = UnconfirmedTransaction(randomUUID().toString, blockHash, System.currentTimeMillis() / 1000L, + "", isUnlocked = false) :: unconfirmedQueue sendUnlockAccount(unconfirmedQueue.head) + context.system.scheduler.scheduleOnce(30 minutes)(retryUnconfirmed()) case response: EthResponse => response.rtype match { case EthRequestType.UNLOCKACC => if (getUnlockResult(response.responseBody)) - unconfirmedQueue = unconfirmedQueue.filter(_.innerId==response.innerId).head.copy(isUnlocked = true) :: - unconfirmedQueue.filter(_.innerId!=response.innerId) + unconfirmedQueue = unconfirmedQueue.filter(_.innerId == response.innerId).head.copy(isUnlocked = true) :: + unconfirmedQueue.filter(_.innerId != response.innerId) sendEthereumTransaction(unconfirmedQueue.head) case EthRequestType.SENDTX => - unconfirmedQueue = unconfirmedQueue.filter(_.innerId==response.innerId) + unconfirmedQueue = unconfirmedQueue.filter(_.innerId == response.innerId) .head.copy(transactionEthID = getTransactionId(response.responseBody)) :: - unconfirmedQueue.filter(_.innerId!=response.innerId) + unconfirmedQueue.filter(_.innerId != response.innerId) sendTransactionReceiptRequest(unconfirmedQueue.head) - case EthRequestType.GETRESULT => if (getTransactionReceipt(response.responseBody)._1){ + case EthRequestType.GETRESULT => if (getTransactionReceipt(response.responseBody)._1) { lastEthBlockHash = getTransactionReceipt(response.responseBody)._2 - unconfirmedQueue = unconfirmedQueue.filter(_.innerId!=response.innerId) + logger.info("transaction with block hash: " + ByteString.toString + + "written in Ethereum block: " + lastEthBlockHash) + unconfirmedQueue = unconfirmedQueue.filter(_.innerId != response.innerId) } } } + def retryUnconfirmed() : Unit = { + unconfirmedQueue = unconfirmedQueue.sortBy(_.timeStamp) + unconfirmedQueue.foreach(e => sendUnlockAccount(e)) + } + def sendEthereumTransaction(transaction: UnconfirmedTransaction): Unit = { val transactionJson: Json = Json.fromFields(List( ("jsonrpc", Json.fromDoubleOrNull(2.0)), @@ -54,7 +64,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { } def sendUnlockAccount(transaction: UnconfirmedTransaction): Unit = { - val jsonToUnlock = Json.fromFields(List ( + val jsonToUnlock = Json.fromFields(List( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("personal_unlockAccount")), ("params", Json.fromValues(List( @@ -69,7 +79,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { } def sendTransactionReceiptRequest(transaction: UnconfirmedTransaction): Unit = { - val requestBody = Json.fromFields(List ( + val requestBody = Json.fromFields(List( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("eth_getTransactionReceipt")), ("params", Json.fromValues(List(Json.fromString(transaction.transactionEthID)))), @@ -81,8 +91,8 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { def getUnlockResult(json: Json): Boolean = json.hcursor.downField("result").as[Boolean].getOrElse(false) - def getTransactionReceipt(json: Json): (Boolean, String) = - (json.hcursor.downField("status").as[String].getOrElse("")=="0x1", + def getTransactionReceipt(json: Json): (Boolean, String) = + (json.hcursor.downField("status").as[String].getOrElse("") == "0x1", json.hcursor.downField("blockHash").as[String].getOrElse("")) def getTransactionId(json: Json): String = json.hcursor.downField("result").as[String].getOrElse("") @@ -93,5 +103,5 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { } -case class UnconfirmedTransaction(innerId: String, blockHash: ByteString, +case class UnconfirmedTransaction(innerId: String, blockHash: ByteString, timeStamp: Long, transactionEthID: String, isUnlocked: Boolean) \ No newline at end of file From a09819225d6c2572f4f89a0d979c77a26060637a Mon Sep 17 00:00:00 2001 From: ugulavaGeorge Date: Mon, 12 Nov 2018 14:43:59 +0300 Subject: [PATCH 12/14] typing, naming fix --- src/main/resources/application.conf | 2 +- src/main/scala/mvp2/actors/Anchorer.scala | 4 +++- src/main/scala/mvp2/utils/Settings.scala | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 2dc5937..75d7403 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -13,7 +13,7 @@ httpPort = 9151 timeout = 10 } - ethereum { + ethereumSettings { userAccount = "" userPassword = "" receiverAccount = "" diff --git a/src/main/scala/mvp2/actors/Anchorer.scala b/src/main/scala/mvp2/actors/Anchorer.scala index 7f082ca..e92bd92 100644 --- a/src/main/scala/mvp2/actors/Anchorer.scala +++ b/src/main/scala/mvp2/actors/Anchorer.scala @@ -7,6 +7,7 @@ import io.circe.Json import mvp2.http.{EthResponse, EthereumService} import mvp2.utils.{EthRequestType, EthereumSettings} import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext.Implicits.global class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { @@ -46,6 +47,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { } def sendEthereumTransaction(transaction: UnconfirmedTransaction): Unit = { + val price = ethereumSettings.gasPrice val transactionJson: Json = Json.fromFields(List( ("jsonrpc", Json.fromDoubleOrNull(2.0)), ("method", Json.fromString("eth_sendTransaction")), @@ -54,7 +56,7 @@ class Anchorer(ethereumSettings: EthereumSettings) extends CommonActor { ("to", Json.fromString(ethereumSettings.receiverAccount)), ("value", Json.fromDoubleOrNull(ethToTransfer)), ("gas", Json.fromString(Integer.toHexString(gasAmount))), - ("gasPrice", Json.fromString(Integer.toHexString(ethereumSettings.gasPrice))), + ("gasPrice", Json.fromString(f"$price%#x")), ("data", Json.fromString(encode2Base16(transaction.blockHash))) ))), ("id", Json.fromInt(1)) diff --git a/src/main/scala/mvp2/utils/Settings.scala b/src/main/scala/mvp2/utils/Settings.scala index 5933e62..ba9c5ea 100644 --- a/src/main/scala/mvp2/utils/Settings.scala +++ b/src/main/scala/mvp2/utils/Settings.scala @@ -20,6 +20,6 @@ case class ApiSettings(httpHost: String, httpPort: Int, timeout: Int) case class InfluxSettings(host: String, port: Int, login: String, password: String) case class EthereumSettings(userAccount: String, userPassword: String, receiverAccount:String, - peerRPCAddress: String, gasPrice: Int) + peerRPCAddress: String, gasPrice: Long) case class TestingSettings(pingPong: Boolean) \ No newline at end of file From a0617f384bc30703195a1ec79648f75bdaade800 Mon Sep 17 00:00:00 2001 From: Stanislav Kapinus Date: Wed, 28 Nov 2018 12:08:03 +0300 Subject: [PATCH 13/14] refactoring --- src/main/scala/mvp2/utils/Settings.scala | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/scala/mvp2/utils/Settings.scala b/src/main/scala/mvp2/utils/Settings.scala index b4bb008..c11231d 100644 --- a/src/main/scala/mvp2/utils/Settings.scala +++ b/src/main/scala/mvp2/utils/Settings.scala @@ -13,10 +13,8 @@ case class Settings(port: Int, ntp: NetworkTimeProviderSettings, influx: InfluxSettings, testingSettings: TestingSettings, - mempoolSetting: MempoolSetting - ethereumSettings: EthereumSettings, - influx: Option[InfluxSettings], - testingSettings: Option[TestingSettings] + mempoolSetting: MempoolSetting, + ethereumSettings: EthereumSettings ) case class Node(host: String, port: Int) @@ -29,10 +27,9 @@ case class NetworkTimeProviderSettings(server: String, updateEvery: Int, timeout case class MempoolSetting(transactionsValidTime: Long, mempoolCleaningTime: Long) -case class TestingSettings(messagesTime: Boolean, iteratorsSyncTime: Int) +case class TestingSettings(messagesTime: Boolean, iteratorsSyncTime: Int, pingPong: Boolean = false) case class NetworkSettings(maxBlockQtyInBlocksMessage: Int) -case class EthereumSettings(userAccount: String, userPassword: String, receiverAccount:String, - peerRPCAddress: String, gasPrice: Long) -case class TestingSettings(pingPong: Boolean) \ No newline at end of file +case class EthereumSettings(userAccount: String, userPassword: String, receiverAccount: String, + peerRPCAddress: String, gasPrice: Long) \ No newline at end of file From c29de26502f68f9620fb2e7b8a86c7085c2e4827 Mon Sep 17 00:00:00 2001 From: Stanislav Kapinus Date: Wed, 28 Nov 2018 12:54:07 +0300 Subject: [PATCH 14/14] refactoring --- src/main/scala/mvp2/utils/Settings.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/mvp2/utils/Settings.scala b/src/main/scala/mvp2/utils/Settings.scala index c11231d..885eda2 100644 --- a/src/main/scala/mvp2/utils/Settings.scala +++ b/src/main/scala/mvp2/utils/Settings.scala @@ -27,7 +27,7 @@ case class NetworkTimeProviderSettings(server: String, updateEvery: Int, timeout case class MempoolSetting(transactionsValidTime: Long, mempoolCleaningTime: Long) -case class TestingSettings(messagesTime: Boolean, iteratorsSyncTime: Int, pingPong: Boolean = false) +case class TestingSettings(messagesTime: Boolean, iteratorsSyncTime: Int) case class NetworkSettings(maxBlockQtyInBlocksMessage: Int)