Skip to content

Commit

Permalink
add refactor from JsonRpcController
Browse files Browse the repository at this point in the history
  • Loading branch information
biandratti committed Oct 28, 2020
1 parent 95ac2d4 commit 235fb7b
Show file tree
Hide file tree
Showing 22 changed files with 360 additions and 82 deletions.
3 changes: 3 additions & 0 deletions src/main/scala/io/iohk/ethereum/faucet/Faucet.scala
Expand Up @@ -5,6 +5,7 @@ import java.security.SecureRandom
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import com.typesafe.config.ConfigFactory
import io.iohk.ethereum.faucet.jsonrpc.FaucetServer
import io.iohk.ethereum.keystore.KeyStoreImpl
import io.iohk.ethereum.mallet.service.RpcClient
import io.iohk.ethereum.utils.{KeyStoreConfig, Logger}
Expand All @@ -29,6 +30,8 @@ object Faucet extends Logger {
case Success(serverBinding) => log.info(s"Faucet HTTP server listening on ${serverBinding.localAddress}")
case Failure(ex) => log.error("Cannot start faucet HTTP server", ex)
}

(new FaucetServer).start()
}

}
9 changes: 8 additions & 1 deletion src/main/scala/io/iohk/ethereum/faucet/FaucetConfig.scala
@@ -1,11 +1,18 @@
package io.iohk.ethereum.faucet

import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher
import com.typesafe.config.{Config => TypesafeConfig}
import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig}
import io.iohk.ethereum.domain.Address
import io.iohk.ethereum.utils.ConfigUtils

import scala.concurrent.duration.{FiniteDuration, _}

trait FaucetConfigBuilder {
lazy val rawConfig: TypesafeConfig = ConfigFactory.load()
lazy val rawMantisConfig: TypesafeConfig = rawConfig.getConfig("mantis")
lazy val faucetConfig: FaucetConfig = FaucetConfig(rawConfig)
}

case class FaucetConfig(
walletAddress: Address,
walletPassword: String,
Expand Down
114 changes: 113 additions & 1 deletion src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetBuilder.scala
@@ -1,3 +1,115 @@
package io.iohk.ethereum.faucet.jsonrpc class FaucetBuilder {
package io.iohk.ethereum.faucet.jsonrpc

import java.security.SecureRandom

import akka.actor.ActorSystem
import io.iohk.ethereum.faucet.FaucetConfigBuilder
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonRpcConfig
import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer
import io.iohk.ethereum.keystore.KeyStoreImpl
import io.iohk.ethereum.mallet.service.RpcClient
import io.iohk.ethereum.nodebuilder.SecureRandomBuilder
import io.iohk.ethereum.utils.{KeyStoreConfig, Logger}

import scala.concurrent.Future


trait ActorSystemBuilder {
def systemName: String
implicit lazy val system: ActorSystem = ActorSystem(systemName)
}

trait FaucetControllerBuilder {
self: FaucetConfigBuilder with ActorSystemBuilder =>

implicit val ec = system.dispatcher

/*private val walletRpcClient =
new WalletRpcClient(faucetConfig.walletRpcAddress, sslContext.toOption)
private val faucetService: FaucetService = new FaucetServiceImpl(walletRpcClient)
*/

}

trait FaucetRpcServiceBuilder {
self: FaucetConfigBuilder with FaucetControllerBuilder with ActorSystemBuilder =>

val keyStore = new KeyStoreImpl(KeyStoreConfig.customKeyStoreConfig(faucetConfig.keyStoreDir), new SecureRandom())
val rpcClient = new RpcClient(faucetConfig.rpcAddress)
val faucetRpcService = new FaucetRpcService(rpcClient, keyStore, faucetConfig)
}

trait FaucetJsonRpcHealthCheckBuilder {
self: FaucetRpcServiceBuilder =>

val faucetJsonRpcHealthCheck = new FaucetJsonRpcHealthCheck(faucetRpcService)
}

trait JsonRpcConfigBuilder { self: FaucetConfigBuilder =>

object Apis {
val Rpc = "rpc"

val available = Seq(Rpc)
}

val availableApis: List[String] = Apis.available.toList //TODO: mmmmm
lazy val jsonRpcConfig: JsonRpcConfig = JsonRpcConfig(rawMantisConfig, Apis.available.toList)
}

trait FaucetJsonRpcControllerBuilder {
self: JsonRpcConfigBuilder with FaucetRpcServiceBuilder =>

val faucetJsonRpcController = new FaucetJsonRpcController(
new FaucetJRC(faucetRpcService, jsonRpcConfig).handleFaucetRequest,
jsonRpcConfig
)
}

trait FaucetJsonRpcHttpServerBuilder {
self: ActorSystemBuilder
with JsonRpcConfigBuilder
with SecureRandomBuilder
with FaucetJsonRpcHealthCheckBuilder
with FaucetJsonRpcControllerBuilder =>

val faucetJsonRpcHttpServer = JsonRpcHttpServer(
faucetJsonRpcController,
faucetJsonRpcHealthCheck,
jsonRpcConfig.httpServerConfig,
secureRandom,
// DispatcherId("midnight.async.dispatchers.json-rpc-http"), //TODO: add dispatcher
//() => sslContext
)
}

class FaucetServer extends
ActorSystemBuilder
with FaucetConfigBuilder
with JsonRpcConfigBuilder
with SecureRandomBuilder
with FaucetControllerBuilder
with FaucetRpcServiceBuilder
with FaucetJsonRpcHealthCheckBuilder
with FaucetJsonRpcControllerBuilder
with FaucetJsonRpcHttpServerBuilder
with Logger {

override def systemName: String = "Faucet-system"

def start(): Unit = {
log.info("About to start Faucet server")

log.info("About to start Faucet JSON-RPC server")
startJsonRpcHttpServer()
}

//TODO: load if jsonRpcConfig.httpServerConfig.enabled
private[this] def startJsonRpcHttpServer() =
faucetJsonRpcHttpServer match {
case Right(jsonRpcServer) => jsonRpcServer.run()
case Left(error) =>
Future.failed(new RuntimeException(s"$error"))
}
}
33 changes: 29 additions & 4 deletions src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala
@@ -1,12 +1,37 @@
package io.iohk.ethereum.faucet.jsonrpc

import akka.util.ByteString
import io.iohk.ethereum.domain.Address
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonDecoder.NoParamsDecoder
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.{JsonDecoder, JsonEncoder}
import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
import org.json4s.JsonAST.{JArray, JObject, JString}

object FucetDomain {
object FaucetDomain {

case class SendFundsRequest(address: String)
case class SendFundsResponse(jobHash: ByteString)
case class SendFundsRequest(address: Address)
object SendFundsRequest extends JsonMethodsImplicits {
implicit val sendFundsRequestDecoder: JsonDecoder[SendFundsRequest] = {
case Some(JArray((input: JString) :: Nil)) => extractAddress(input).map(SendFundsRequest(_))
case _ => Left(InvalidParams())
}
}

case class SendFundsResponse(txId: ByteString)
object SendFundsResponse extends JsonMethodsImplicits {
implicit val sendFundsResponseEncoder: JsonEncoder[SendFundsResponse] = (t: SendFundsResponse) => encodeAsHex(t.txId)
}

case class StatusRequest()
case class StatusResponse(status: FaucetStatus)
object StatusRequest extends JsonMethodsImplicits {
implicit val statusRequestDecoder: JsonDecoder[StatusRequest] = new NoParamsDecoder(StatusRequest())
}

case class StatusResponse(status: String)
object StatusResponse extends JsonMethodsImplicits {
implicit val statusEncoder: JsonEncoder[StatusResponse] = (t: StatusResponse) => JObject(
"status" -> JString(t.status)
)
}
}
35 changes: 34 additions & 1 deletion src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJRC.scala
@@ -1,3 +1,36 @@
package io.iohk.ethereum.faucet.jsonrpc class FaucetJRC {
package io.iohk.ethereum.faucet.jsonrpc

import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain._
import io.iohk.ethereum.jsonrpc.JsonRpcController.Apis
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonRpcConfig
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon
import io.iohk.ethereum.jsonrpc.{JsonRpcRequest, JsonRpcResponse}

import scala.concurrent.Future

class FaucetJRC(
faucetRpcService: FaucetRpcService,
override val config: JsonRpcConfig
) extends JsonRpcControllerCommon {

override def enabledApis: Seq[String] = config.apis :+ Apis.Rpc

override def handleFn: Map[String, PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]]] = Map(
Apis.Eth -> handleFaucetRequest,
)

def handleFaucetRequest: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {
case req @ JsonRpcRequest(_, FaucetJRC.SendFunds, _, _) =>
handle[SendFundsRequest, SendFundsResponse](faucetRpcService.sendFunds, req)
case req @ JsonRpcRequest(_, FaucetJRC.Status, _, _) =>
handle[StatusRequest, StatusResponse](faucetRpcService.status, req)
}
}

object FaucetJRC {
private val Prefix = "faucet_"

val SendFunds: String = Prefix + "sendFunds"
val Status: String = Prefix + "status"
}

@@ -1,16 +1,24 @@
package io.iohk.ethereum.faucet.jsonrpc

import io.iohk.ethereum.jsonrpc.{JsonRpcController, JsonRpcRequest, JsonRpcResponse}
import io.iohk.ethereum.jsonrpc.JsonRpcController.Apis
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.MethodNotFound
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon
import io.iohk.ethereum.jsonrpc.{JsonRpcRequest, JsonRpcResponse}

import scala.concurrent.Future

class FaucetJsonRpcController(
faucetHandleFn: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]],
override val config: JsonRpcController.JsonRpcConfig
override val config: JsonRpcControllerCommon.JsonRpcConfig
) extends JsonRpcControllerCommon {

override def handleFn: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {
override def enabledApis: Seq[String] = config.apis :+ Apis.Rpc //TODO: add param

override def handleFn: Map[String, PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]]] = Map(
Apis.Eth -> handleFaucetRequest,
)

def handleFaucetRequest: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {
case req =>
val notFoundFn: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {
case _ => Future.successful(errorResponse(req, MethodNotFound))
Expand Down
@@ -1,15 +1,17 @@
package io.iohk.ethereum.faucet.jsonrpc

import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest
import io.iohk.ethereum.healthcheck.HealthcheckResponse
import io.iohk.ethereum.jsonrpc.{JsonRpcHealthChecker, JsonRpcHealthcheck}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class FaucetJsonRpcHealthCheck(faucetService: FaucetRpcService) extends JsonRpcHealthChecker {
class FaucetJsonRpcHealthCheck(faucetRpcService: FaucetRpcService) extends JsonRpcHealthChecker {

protected def mainService: String = "faucet health"

final val statusHC = JsonRpcHealthcheck("status", () => faucetService.status(StatusRequest()))
final val statusHC = JsonRpcHealthcheck("status", () => faucetRpcService.status(StatusRequest()))

override def healthCheck(): Future[HealthcheckResponse] = {
val statusF = statusHC()
Expand Down
@@ -1,5 +1,70 @@
package io.iohk.ethereum.faucet.jsonrpc

class FaucetRpcService {
import java.time.Clock

import akka.http.scaladsl.model.RemoteAddress
import akka.util.ByteString
import com.twitter.util.LruMap
import io.iohk.ethereum.domain.{Address, Transaction}
import io.iohk.ethereum.faucet.FaucetConfig
import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.{SendFundsRequest, SendFundsResponse, StatusRequest, StatusResponse}
import io.iohk.ethereum.jsonrpc.ServiceResponse
import io.iohk.ethereum.keystore.KeyStore
import io.iohk.ethereum.mallet.service.RpcClient
import io.iohk.ethereum.network.p2p.messages.CommonMessages.SignedTransactions.SignedTransactionEnc
import io.iohk.ethereum.rlp
import io.iohk.ethereum.utils.{ByteStringUtils, Logger}

import scala.concurrent.Future

class FaucetRpcService(rpcClient: RpcClient, keyStore: KeyStore, config: FaucetConfig, clock: Clock = Clock.systemUTC())
extends Logger {

private val latestRequestTimestamps = new LruMap[RemoteAddress, Long](config.latestTimestampCacheSize)

private val wallet = keyStore.unlockAccount(config.walletAddress, config.walletPassword) match {
case Right(w) => w
case Left(err) =>
throw new RuntimeException(s"Cannot unlock wallet for use in faucet (${config.walletAddress}), because of $err")
}

def sendFunds(sendFundsRequest: SendFundsRequest): ServiceResponse[SendFundsResponse] = {
val clientAddr: RemoteAddress = ???
val targetAddress: String = ???
val timeMillis = clock.instant().toEpochMilli
val latestRequestTimestamp = latestRequestTimestamps.getOrElse(clientAddr, 0L)
if (latestRequestTimestamp + config.minRequestInterval.toMillis < timeMillis) {
latestRequestTimestamps.put(clientAddr, timeMillis)

val res = for {
nonce <- rpcClient.getNonce(wallet.address)
txId <- rpcClient.sendTransaction(prepareTx(Address(targetAddress), nonce))
} yield txId

res match {
case Right(txId) =>
val txIdHex = s"0x${ByteStringUtils.hash2string(txId)}"
log.info(s"Sending ${config.txValue} ETH to $targetAddress in tx: $txIdHex. Requested by $clientAddr")
//complete(StatusCodes.OK, txIdHex)
Future.successful(Right(SendFundsResponse(txId))) //TODO: change...

case Left(err) =>
log.error(s"An error occurred while using faucet: $err")
Future.successful(???)
//complete(StatusCodes.InternalServerError)
}
} else Future.successful(???)//complete(StatusCodes.TooManyRequests)
}

private def prepareTx(targetAddress: Address, nonce: BigInt): ByteString = {
val transaction =
Transaction(nonce, config.txGasPrice, config.txGasLimit, Some(targetAddress), config.txValue, ByteString())

val stx = wallet.signTx(transaction, None)
ByteString(rlp.encode(stx.tx.toRLPEncodable))
}

def status(statusRequest: StatusRequest): ServiceResponse[StatusResponse] = {
Future.successful(Right(StatusResponse("ok")))
}
}
Expand Up @@ -3,7 +3,7 @@ package io.iohk.ethereum.jsonrpc
import akka.util.ByteString
import io.iohk.ethereum.crypto.ECDSASignature
import io.iohk.ethereum.jsonrpc.CheckpointingService._
import io.iohk.ethereum.jsonrpc.JsonRpcController.Codec
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.Codec
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
import io.iohk.ethereum.jsonrpc.JsonSerializers.QuantitiesSerializer
import org.json4s.JsonAST._
Expand Down
@@ -1,8 +1,8 @@
package io.iohk.ethereum.jsonrpc

import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse}
import io.iohk.ethereum.jsonrpc.JsonRpcController.{Codec, JsonEncoder}
import io.iohk.ethereum.jsonrpc.JsonRpcController.JsonDecoder.NoParamsDecoder
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.{Codec, JsonEncoder}
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonDecoder.NoParamsDecoder
import org.json4s.JsonAST.{JArray, JString, JValue}

object DebugJsonMethodsImplicits extends JsonMethodsImplicits {
Expand Down
Expand Up @@ -2,10 +2,10 @@ package io.iohk.ethereum.jsonrpc

import akka.util.ByteString
import io.iohk.ethereum.jsonrpc.EthService._
import io.iohk.ethereum.jsonrpc.JsonRpcController.JsonDecoder.NoParamsDecoder
import io.iohk.ethereum.jsonrpc.JsonRpcController.{Codec, JsonDecoder, JsonEncoder}
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
import io.iohk.ethereum.jsonrpc.PersonalService.{SendTransactionRequest, SendTransactionResponse, SignRequest}
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonDecoder.NoParamsDecoder
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon._
import org.json4s.{Extraction, JsonAST}
import org.json4s.JsonAST.{JArray, JBool, JString, JValue, _}
import org.json4s.JsonDSL._
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala
Expand Up @@ -14,7 +14,7 @@ import io.iohk.ethereum.db.storage.AppStateStorage
import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation
import io.iohk.ethereum.domain.{BlockHeader, SignedTransaction, UInt256, _}
import io.iohk.ethereum.jsonrpc.FilterManager.{FilterChanges, FilterLogs, LogFilterLogs, TxLog}
import io.iohk.ethereum.jsonrpc.JsonRpcController.JsonRpcConfig
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcControllerCommon.JsonRpcConfig
import io.iohk.ethereum.keystore.KeyStore
import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, Ledger, StxLedger}
import io.iohk.ethereum.ommers.OmmersPool
Expand Down

0 comments on commit 235fb7b

Please sign in to comment.