Skip to content

Commit

Permalink
[ETCM-110] Make decoding parameterless requests uniform
Browse files Browse the repository at this point in the history
  • Loading branch information
kapke committed Sep 22, 2020
1 parent 4a5f371 commit d7fa62c
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 89 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project/plugins/project/
.ensime
.ensime_cache/
.bloop
out/

# IDE folders
.idea/
Expand All @@ -20,4 +21,4 @@ metals.sbt
.evm-runner_history

# Nix
result
result
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package io.iohk.ethereum.jsonrpc

import io.iohk.ethereum.jsonrpc.DebugService.{ ListPeersInfoRequest, ListPeersInfoResponse }
import org.json4s.JsonAST.{ JArray, JString, JValue }
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 org.json4s.JsonAST.{JArray, JString, JValue}

object DebugJsonMethodsImplicits extends JsonMethodsImplicits {

implicit val debug_listPeersInfo: Codec[ListPeersInfoRequest, ListPeersInfoResponse] =
new Codec[ListPeersInfoRequest, ListPeersInfoResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, ListPeersInfoRequest] =
Right(ListPeersInfoRequest())

new NoParamsDecoder(ListPeersInfoRequest()) with JsonEncoder[ListPeersInfoResponse] {
def encodeJson(t: ListPeersInfoResponse): JValue =
JArray(t.peers.map(a => JString(a.toString)))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package io.iohk.ethereum.jsonrpc

import akka.util.ByteString
import io.iohk.ethereum.jsonrpc.EthService._
import io.iohk.ethereum.jsonrpc.JsonRpcController.{JsonDecoder, JsonEncoder}
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 org.json4s.{Extraction, JsonAST}
Expand All @@ -12,28 +13,17 @@ import org.json4s.JsonDSL._
// scalastyle:off number.of.methods
object EthJsonMethodsImplicits extends JsonMethodsImplicits {

implicit val eth_protocolVersion = new JsonDecoder[ProtocolVersionRequest] with JsonEncoder[ProtocolVersionResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, ProtocolVersionRequest] = Right(
ProtocolVersionRequest()
)

implicit val eth_protocolVersion = new NoParamsDecoder(ProtocolVersionRequest())
with JsonEncoder[ProtocolVersionResponse] {
def encodeJson(t: ProtocolVersionResponse): JValue = t.value
}

implicit val eth_chainId = new JsonDecoder[ChainIdRequest] with JsonEncoder[ChainIdResponse] {
def decodeJson(params: Option[JArray]) = params match {
case None | Some(JArray(Nil)) => Right(ChainIdRequest())
case other => Left(InvalidParams("eth_chainId method does not take params"))
}

implicit val eth_chainId = new NoParamsDecoder(ChainIdRequest()) with JsonEncoder[ChainIdResponse] {
def encodeJson(t: ChainIdResponse) = encodeAsHex(t.value)
}

implicit val eth_blockNumber = new JsonDecoder[BestBlockNumberRequest] with JsonEncoder[BestBlockNumberResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, BestBlockNumberRequest] = Right(
BestBlockNumberRequest()
)

implicit val eth_blockNumber = new NoParamsDecoder(BestBlockNumberRequest())
with JsonEncoder[BestBlockNumberResponse] {
override def encodeJson(t: BestBlockNumberResponse): JValue = Extraction.decompose(t.bestBlockNumber)
}

Expand All @@ -53,50 +43,25 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits {
override def encodeJson(t: SubmitHashRateResponse): JValue = JBool(t.success)
}

implicit val eth_gasPrice = new JsonDecoder[GetGasPriceRequest] with JsonEncoder[GetGasPriceResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetGasPriceRequest] = params match {
case None | Some(JArray(Nil)) => Right(GetGasPriceRequest())
case Some(_) => Left(InvalidParams())
}

implicit val eth_gasPrice = new NoParamsDecoder(GetGasPriceRequest()) with JsonEncoder[GetGasPriceResponse] {
override def encodeJson(t: GetGasPriceResponse): JValue = encodeAsHex(t.price)
}

implicit val eth_mining = new JsonDecoder[GetMiningRequest] with JsonEncoder[GetMiningResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetMiningRequest] = params match {
case None | Some(JArray(Nil)) => Right(GetMiningRequest())
case Some(_) => Left(InvalidParams())
}

implicit val eth_mining = new NoParamsDecoder(GetMiningRequest()) with JsonEncoder[GetMiningResponse] {
override def encodeJson(t: GetMiningResponse): JValue = JBool(t.isMining)
}

implicit val eth_hashrate = new JsonDecoder[GetHashRateRequest] with JsonEncoder[GetHashRateResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetHashRateRequest] = params match {
case None | Some(JArray(Nil)) => Right(GetHashRateRequest())
case Some(_) => Left(InvalidParams())
}

implicit val eth_hashrate = new NoParamsDecoder(GetHashRateRequest()) with JsonEncoder[GetHashRateResponse] {
override def encodeJson(t: GetHashRateResponse): JsonAST.JValue = encodeAsHex(t.hashRate)
}

implicit val eth_coinbase = new JsonDecoder[GetCoinbaseRequest] with JsonEncoder[GetCoinbaseResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetCoinbaseRequest] = params match {
case None | Some(JArray(Nil)) => Right(GetCoinbaseRequest())
case Some(_) => Left(InvalidParams())
}

implicit val eth_coinbase = new NoParamsDecoder(GetCoinbaseRequest()) with JsonEncoder[GetCoinbaseResponse] {
override def encodeJson(t: GetCoinbaseResponse): JsonAST.JValue = {
encodeAsHex(t.address.bytes)
}
}

implicit val eth_getWork = new JsonDecoder[GetWorkRequest] with JsonEncoder[GetWorkResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetWorkRequest] = params match {
case None | Some(JArray(Nil)) => Right(GetWorkRequest())
case Some(_) => Left(InvalidParams())
}

implicit val eth_getWork = new NoParamsDecoder(GetWorkRequest()) with JsonEncoder[GetWorkResponse] {
override def encodeJson(t: GetWorkResponse): JsonAST.JValue = {
val powHeaderHash = encodeAsHex(t.powHeaderHash)
val dagSeed = encodeAsHex(t.dagSeed)
Expand Down Expand Up @@ -267,9 +232,7 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits {
}
}

implicit val eth_syncing = new JsonDecoder[SyncingRequest] with JsonEncoder[SyncingResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, SyncingRequest] = Right(SyncingRequest())

implicit val eth_syncing = new NoParamsDecoder(SyncingRequest()) with JsonEncoder[SyncingResponse] {
def encodeJson(t: SyncingResponse): JValue = t.syncStatus match {
case Some(syncStatus) => Extraction.decompose(syncStatus)
case None => false
Expand Down Expand Up @@ -445,15 +408,9 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits {
}
}

implicit val eth_newBlockFilter = new JsonDecoder[NewBlockFilterRequest] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, NewBlockFilterRequest] =
Right(NewBlockFilterRequest())
}
implicit val eth_newBlockFilter = new NoParamsDecoder(NewBlockFilterRequest()) {}

implicit val eth_newPendingTransactionFilter = new JsonDecoder[NewPendingTransactionFilterRequest] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, NewPendingTransactionFilterRequest] =
Right(NewPendingTransactionFilterRequest())
}
implicit val eth_newPendingTransactionFilter = new NoParamsDecoder(NewPendingTransactionFilterRequest()) {}

implicit val eth_uninstallFilter = new JsonDecoder[UninstallFilterRequest] with JsonEncoder[UninstallFilterResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, UninstallFilterRequest] =
Expand Down
26 changes: 9 additions & 17 deletions src/main/scala/io/iohk/ethereum/jsonrpc/JsonMethodsImplicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import akka.util.ByteString
import io.iohk.ethereum.crypto.ECDSASignature
import io.iohk.ethereum.domain.Address
import io.iohk.ethereum.jsonrpc.EthService.BlockParam
import io.iohk.ethereum.jsonrpc.JsonRpcController.{JsonDecoder, JsonEncoder}
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.JsonSerializers.{
AddressJsonSerializer,
Expand All @@ -27,8 +28,6 @@ import scala.util.Try

trait JsonMethodsImplicits {

trait Codec[Req, Res] extends JsonDecoder[Req] with JsonEncoder[Res]

implicit val formats: Formats = DefaultFormats.preservingEmptyValues + OptionNoneToJNullSerializer +
QuantitiesSerializer + UnformattedDataJsonSerializer + AddressJsonSerializer

Expand Down Expand Up @@ -165,25 +164,20 @@ object JsonMethodsImplicits extends JsonMethodsImplicits {
override def encodeJson(t: Sha3Response): JValue = encodeAsHex(t.data)
}

implicit val web3_clientVersion = new JsonDecoder[ClientVersionRequest] with JsonEncoder[ClientVersionResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, ClientVersionRequest] = Right(
ClientVersionRequest()
)
implicit val web3_clientVersion = new NoParamsDecoder(ClientVersionRequest())
with JsonEncoder[ClientVersionResponse] {
override def encodeJson(t: ClientVersionResponse): JValue = t.value
}

implicit val net_version = new JsonDecoder[VersionRequest] with JsonEncoder[VersionResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, VersionRequest] = Right(VersionRequest())
implicit val net_version = new NoParamsDecoder(VersionRequest()) with JsonEncoder[VersionResponse] {
override def encodeJson(t: VersionResponse): JValue = t.value
}

implicit val net_listening = new JsonDecoder[ListeningRequest] with JsonEncoder[ListeningResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, ListeningRequest] = Right(ListeningRequest())
implicit val net_listening = new NoParamsDecoder(ListeningRequest()) with JsonEncoder[ListeningResponse] {
override def encodeJson(t: ListeningResponse): JValue = t.value
}

implicit val net_peerCount = new JsonDecoder[PeerCountRequest] with JsonEncoder[PeerCountResponse] {
override def decodeJson(params: Option[JArray]): Either[JsonRpcError, PeerCountRequest] = Right(PeerCountRequest())
implicit val net_peerCount = new NoParamsDecoder(PeerCountRequest()) with JsonEncoder[PeerCountResponse] {
override def encodeJson(t: PeerCountResponse): JValue = encodeAsHex(t.value)
}

Expand Down Expand Up @@ -213,10 +207,8 @@ object JsonMethodsImplicits extends JsonMethodsImplicits {
JString(t.address.toString)
}

implicit val personal_listAccounts = new JsonDecoder[ListAccountsRequest] with JsonEncoder[ListAccountsResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, ListAccountsRequest] =
Right(ListAccountsRequest())

implicit val personal_listAccounts = new NoParamsDecoder(ListAccountsRequest())
with JsonEncoder[ListAccountsResponse] {
def encodeJson(t: ListAccountsResponse): JValue =
JArray(t.addresses.map(a => JString(a.toString)))
}
Expand Down
23 changes: 23 additions & 0 deletions src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import org.json4s.JsonAST.{JArray, JValue}
import org.json4s.JsonDSL._
import com.typesafe.config.{Config => TypesafeConfig}
import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse}
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
import io.iohk.ethereum.jsonrpc.QAService.{GetPendingTransactionsRequest, GetPendingTransactionsResponse}
import io.iohk.ethereum.jsonrpc.TestService._
import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig
import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.FiniteDuration
Expand All @@ -23,11 +25,32 @@ object JsonRpcController {
trait JsonDecoder[T] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, T]
}
object JsonDecoder {
abstract class NoParamsDecoder[T](request: => T) extends JsonDecoder[T] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, T] =
params match {
case None | Some(JArray(Nil)) => Right(request)
case _ => Left(InvalidParams(s"No parameters expected"))
}
}
}

trait JsonEncoder[T] {
def encodeJson(t: T): JValue
}

trait Codec[Req, Res] extends JsonDecoder[Req] with JsonEncoder[Res]
object Codec {
import scala.language.implicitConversions

implicit def decoderWithEncoderIntoCodec[Req, Res](
decEnc: JsonDecoder[Req] with JsonEncoder[Res]
): Codec[Req, Res] = new Codec[Req, Res] {
def decodeJson(params: Option[JArray]) = decEnc.decodeJson(params)
def encodeJson(t: Res) = decEnc.encodeJson(t)
}
}

trait JsonRpcConfig {
def apis: Seq[String]
def accountTransactionsMaxBlocks: Int
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.iohk.ethereum.jsonrpc

import io.iohk.ethereum.jsonrpc.JsonRpcController.JsonDecoder.NoParamsDecoder
import io.iohk.ethereum.jsonrpc.JsonRpcController.{Codec, JsonEncoder}
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
import io.iohk.ethereum.jsonrpc.QAService.{
GetPendingTransactionsRequest,
Expand Down Expand Up @@ -36,13 +38,7 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits {
}

implicit val qa_getPendingTransactions: Codec[GetPendingTransactionsRequest, GetPendingTransactionsResponse] =
new Codec[GetPendingTransactionsRequest, GetPendingTransactionsResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetPendingTransactionsRequest] =
params match {
case Some(JArray(Nil)) | None => Right(GetPendingTransactionsRequest())
case _ => Left(InvalidParams())
}

new NoParamsDecoder(GetPendingTransactionsRequest()) with JsonEncoder[GetPendingTransactionsResponse] {
def encodeJson(t: GetPendingTransactionsResponse): JValue =
JArray(t.pendingTransactions.toList.map { pendingTx: PendingTransaction =>
encodeAsHex(pendingTx.stx.tx.hash)
Expand Down

0 comments on commit d7fa62c

Please sign in to comment.