Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ETCM-518] Refactor EthService by adding EthBlocksSevice - service th…
…at handles RPC calls related to blocks
- Loading branch information
Leonor Boga
authored and
Jaap van der Plas
committed
Jan 20, 2021
1 parent
b0116d5
commit 1628997
Showing
17 changed files
with
1,005 additions
and
836 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package io.iohk.ethereum.jsonrpc | ||
|
||
import akka.util.ByteString | ||
import io.iohk.ethereum.domain.Blockchain | ||
import io.iohk.ethereum.jsonrpc.EthService.{BlockParam, ResolvedBlock} | ||
import io.iohk.ethereum.ledger.Ledger | ||
import io.iohk.ethereum.utils.{BlockchainConfig, Logger} | ||
import monix.eval.Task | ||
import org.bouncycastle.util.encoders.Hex | ||
|
||
//eth_call -> ethService.call. // not moved | ||
|
||
object EthBlocksService { | ||
case class ChainIdRequest() | ||
case class ChainIdResponse(value: Byte) | ||
|
||
case class BestBlockNumberRequest() | ||
case class BestBlockNumberResponse(bestBlockNumber: BigInt) | ||
|
||
case class TxCountByBlockHashRequest(blockHash: ByteString) | ||
case class TxCountByBlockHashResponse(txsQuantity: Option[Int]) | ||
|
||
case class BlockByBlockHashRequest(blockHash: ByteString, fullTxs: Boolean) | ||
case class BlockByBlockHashResponse(blockResponse: Option[BlockResponse]) | ||
|
||
case class BlockByNumberRequest(block: BlockParam, fullTxs: Boolean) | ||
case class BlockByNumberResponse(blockResponse: Option[BlockResponse]) | ||
|
||
case class GetBlockTransactionCountByNumberRequest(block: BlockParam) | ||
case class GetBlockTransactionCountByNumberResponse(result: BigInt) | ||
|
||
case class UncleByBlockHashAndIndexRequest(blockHash: ByteString, uncleIndex: BigInt) | ||
case class UncleByBlockHashAndIndexResponse(uncleBlockResponse: Option[BlockResponse]) | ||
|
||
case class UncleByBlockNumberAndIndexRequest(block: BlockParam, uncleIndex: BigInt) | ||
case class UncleByBlockNumberAndIndexResponse(uncleBlockResponse: Option[BlockResponse]) | ||
|
||
case class GetUncleCountByBlockNumberRequest(block: BlockParam) | ||
case class GetUncleCountByBlockNumberResponse(result: BigInt) | ||
|
||
case class GetUncleCountByBlockHashRequest(blockHash: ByteString) | ||
case class GetUncleCountByBlockHashResponse(result: BigInt) | ||
} | ||
|
||
class EthBlocksService(blockchain: Blockchain, ledger: Ledger, blockchainConfig: BlockchainConfig) extends Logger { | ||
import EthBlocksService._ | ||
|
||
private[jsonrpc] def consensus = ledger.consensus | ||
private[jsonrpc] def blockGenerator = consensus.blockGenerator | ||
|
||
def chainId(req: ChainIdRequest): ServiceResponse[ChainIdResponse] = | ||
Task.now(Right(ChainIdResponse(blockchainConfig.chainId))) | ||
|
||
/** | ||
* eth_blockNumber that returns the number of most recent block. | ||
* | ||
* @return Current block number the client is on. | ||
*/ | ||
def bestBlockNumber(req: BestBlockNumberRequest): ServiceResponse[BestBlockNumberResponse] = Task { | ||
Right(BestBlockNumberResponse(blockchain.getBestBlockNumber())) | ||
} | ||
|
||
/** | ||
* Implements the eth_getBlockTransactionCountByHash method that fetches the number of txs that a certain block has. | ||
* | ||
* @param request with the hash of the block requested | ||
* @return the number of txs that the block has or None if the client doesn't have the block requested | ||
*/ | ||
def getBlockTransactionCountByHash(request: TxCountByBlockHashRequest): ServiceResponse[TxCountByBlockHashResponse] = | ||
Task { | ||
val txsCount = blockchain.getBlockBodyByHash(request.blockHash).map(_.transactionList.size) | ||
Right(TxCountByBlockHashResponse(txsCount)) | ||
} | ||
|
||
/** | ||
* Implements the eth_getBlockByHash method that fetches a requested block. | ||
* | ||
* @param request with the hash of the block requested | ||
* @return the block requested or None if the client doesn't have the block | ||
*/ | ||
def getByBlockHash(request: BlockByBlockHashRequest): ServiceResponse[BlockByBlockHashResponse] = Task { | ||
val BlockByBlockHashRequest(blockHash, fullTxs) = request | ||
val blockOpt = blockchain.getBlockByHash(blockHash) | ||
val weight = blockchain.getChainWeightByHash(blockHash) | ||
|
||
val blockResponseOpt = blockOpt.map(block => BlockResponse(block, weight, fullTxs = fullTxs)) | ||
Right(BlockByBlockHashResponse(blockResponseOpt)) | ||
} | ||
|
||
/** | ||
* Implements the eth_getBlockByNumber method that fetches a requested block. | ||
* | ||
* @param request with the block requested (by it's number or by tag) | ||
* @return the block requested or None if the client doesn't have the block | ||
*/ | ||
def getBlockByNumber(request: BlockByNumberRequest): ServiceResponse[BlockByNumberResponse] = Task { | ||
val BlockByNumberRequest(blockParam, fullTxs) = request | ||
val blockResponseOpt = EthService.resolveBlock(blockParam, blockchain, blockGenerator).toOption.map { | ||
case ResolvedBlock(block, pending) => | ||
val weight = blockchain.getChainWeightByHash(block.header.hash) | ||
BlockResponse(block, weight, fullTxs = fullTxs, pendingBlock = pending.isDefined) | ||
} | ||
Right(BlockByNumberResponse(blockResponseOpt)) | ||
} | ||
|
||
def getBlockTransactionCountByNumber( | ||
req: GetBlockTransactionCountByNumberRequest | ||
): ServiceResponse[GetBlockTransactionCountByNumberResponse] = { | ||
Task { | ||
EthService.resolveBlock(req.block, blockchain, blockGenerator).map { case ResolvedBlock(block, _) => | ||
GetBlockTransactionCountByNumberResponse(block.body.transactionList.size) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Implements the eth_getUncleByBlockHashAndIndex method that fetches an uncle from a certain index in a requested block. | ||
* | ||
* @param request with the hash of the block and the index of the uncle requested | ||
* @return the uncle that the block has at the given index or None if the client doesn't have the block or if there's no uncle in that index | ||
*/ | ||
def getUncleByBlockHashAndIndex( | ||
request: UncleByBlockHashAndIndexRequest | ||
): ServiceResponse[UncleByBlockHashAndIndexResponse] = Task { | ||
val UncleByBlockHashAndIndexRequest(blockHash, uncleIndex) = request | ||
val uncleHeaderOpt = blockchain | ||
.getBlockBodyByHash(blockHash) | ||
.flatMap { body => | ||
if (uncleIndex >= 0 && uncleIndex < body.uncleNodesList.size) | ||
Some(body.uncleNodesList.apply(uncleIndex.toInt)) | ||
else | ||
None | ||
} | ||
val weight = uncleHeaderOpt.flatMap(uncleHeader => blockchain.getChainWeightByHash(uncleHeader.hash)) | ||
|
||
//The block in the response will not have any txs or uncles | ||
val uncleBlockResponseOpt = uncleHeaderOpt.map { uncleHeader => | ||
BlockResponse(blockHeader = uncleHeader, weight = weight, pendingBlock = false) | ||
} | ||
Right(UncleByBlockHashAndIndexResponse(uncleBlockResponseOpt)) | ||
} | ||
|
||
/** | ||
* Implements the eth_getUncleByBlockNumberAndIndex method that fetches an uncle from a certain index in a requested block. | ||
* | ||
* @param request with the number/tag of the block and the index of the uncle requested | ||
* @return the uncle that the block has at the given index or None if the client doesn't have the block or if there's no uncle in that index | ||
*/ | ||
def getUncleByBlockNumberAndIndex( | ||
request: UncleByBlockNumberAndIndexRequest | ||
): ServiceResponse[UncleByBlockNumberAndIndexResponse] = Task { | ||
val UncleByBlockNumberAndIndexRequest(blockParam, uncleIndex) = request | ||
val uncleBlockResponseOpt = EthService | ||
.resolveBlock(blockParam, blockchain, blockGenerator) | ||
.toOption | ||
.flatMap { case ResolvedBlock(block, pending) => | ||
if (uncleIndex >= 0 && uncleIndex < block.body.uncleNodesList.size) { | ||
val uncleHeader = block.body.uncleNodesList.apply(uncleIndex.toInt) | ||
val weight = blockchain.getChainWeightByHash(uncleHeader.hash) | ||
|
||
//The block in the response will not have any txs or uncles | ||
Some( | ||
BlockResponse( | ||
blockHeader = uncleHeader, | ||
weight = weight, | ||
pendingBlock = pending.isDefined | ||
) | ||
) | ||
} else | ||
None | ||
} | ||
|
||
Right(UncleByBlockNumberAndIndexResponse(uncleBlockResponseOpt)) | ||
} | ||
|
||
def getUncleCountByBlockNumber( | ||
req: GetUncleCountByBlockNumberRequest | ||
): ServiceResponse[GetUncleCountByBlockNumberResponse] = { | ||
Task { | ||
EthService.resolveBlock(req.block, blockchain, blockGenerator).map { case ResolvedBlock(block, _) => | ||
GetUncleCountByBlockNumberResponse(block.body.uncleNodesList.size) | ||
} | ||
} | ||
} | ||
|
||
def getUncleCountByBlockHash( | ||
req: GetUncleCountByBlockHashRequest | ||
): ServiceResponse[GetUncleCountByBlockHashResponse] = { | ||
Task { | ||
blockchain.getBlockBodyByHash(req.blockHash) match { | ||
case Some(blockBody) => | ||
Right(GetUncleCountByBlockHashResponse(blockBody.uncleNodesList.size)) | ||
case None => | ||
Left( | ||
JsonRpcError.InvalidParams(s"Block with hash ${Hex.toHexString(req.blockHash.toArray[Byte])} not found") | ||
) | ||
} | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
src/main/scala/io/iohk/ethereum/jsonrpc/EthJsonMethodsImplicits.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.