diff --git a/server/app/com/xsn/explorer/services/BlockService.scala b/server/app/com/xsn/explorer/services/BlockService.scala index 3224b96..9f77c50 100644 --- a/server/app/com/xsn/explorer/services/BlockService.scala +++ b/server/app/com/xsn/explorer/services/BlockService.scala @@ -9,6 +9,7 @@ import com.xsn.explorer.models._ import com.xsn.explorer.models.rpc.{Block, TransactionVIN} import com.xsn.explorer.services.logic.{BlockLogic, TransactionLogic} import org.scalactic.Good +import play.api.libs.json.JsValue import scala.concurrent.{ExecutionContext, Future} @@ -18,6 +19,27 @@ class BlockService @Inject() ( transactionLogic: TransactionLogic)( implicit ec: ExecutionContext) { + def getRawBlock(blockhashString: String): FutureApplicationResult[JsValue] = { + val result = for { + blockhash <- blockLogic + .getBlockhash(blockhashString) + .toFutureOr + + block <- xsnService.getRawBlock(blockhash).toFutureOr + } yield block + + result.toFuture + } + + def getRawBlock(height: Height): FutureApplicationResult[JsValue] = { + val result = for { + blockhash <- xsnService.getBlockhash(height).toFutureOr + block <- xsnService.getRawBlock(blockhash).toFutureOr + } yield block + + result.toFuture + } + def getDetails(blockhashString: String): FutureApplicationResult[BlockDetails] = { val result = for { blockhash <- blockLogic diff --git a/server/app/controllers/BlocksController.scala b/server/app/controllers/BlocksController.scala index ab25ba9..9c75833 100644 --- a/server/app/controllers/BlocksController.scala +++ b/server/app/controllers/BlocksController.scala @@ -28,4 +28,11 @@ class BlocksController @Inject() ( .map(blockService.getDetails) .getOrElse(blockService.getDetails(query)) } + + def getRawBlock(query: String) = publicNoInput { _ => + Try(query.toInt) + .map(Height.apply) + .map(blockService.getRawBlock) + .getOrElse(blockService.getRawBlock(query)) + } } diff --git a/server/conf/routes b/server/conf/routes index 1d5147a..a5e9a16 100644 --- a/server/conf/routes +++ b/server/conf/routes @@ -12,6 +12,7 @@ GET /addresses/:address controllers.AddressesController.getDetails(address: GET /blocks controllers.BlocksController.getLatestBlocks() GET /blocks/:query controllers.BlocksController.getDetails(query: String) +GET /blocks/:query/raw controllers.BlocksController.getRawBlock(query: String) GET /stats controllers.StatisticsController.getStatus() diff --git a/server/test/controllers/BlocksControllerSpec.scala b/server/test/controllers/BlocksControllerSpec.scala index e3347dc..bd3b1df 100644 --- a/server/test/controllers/BlocksControllerSpec.scala +++ b/server/test/controllers/BlocksControllerSpec.scala @@ -60,6 +60,17 @@ class BlocksControllerSpec extends MyAPISpec { Future.successful(result) } + override def getRawBlock(blockhash: Blockhash): FutureApplicationResult[JsValue] = { + val result = blocks.get(blockhash) + .map { _ => BlockLoader.json(blockhash.string) } + .map(Good(_)) + .getOrElse { + Bad(BlockNotFoundError).accumulating + } + + Future.successful(result) + } + override def getBlockhash(height: Height): FutureApplicationResult[Blockhash] = { val result = blocks .values @@ -359,4 +370,28 @@ class BlocksControllerSpec extends MyAPISpec { (error \ "message").as[String].nonEmpty mustEqual true } } + + "GET /blocks/:query/raw" should { + def url(query: String) = s"/blocks/$query/raw" + + "retrieve a block by blockhash" in { + val block = posBlock + val response = GET(url(block.hash.string)) + + status(response) mustEqual OK + + val json = contentAsJson(response) + json mustEqual BlockLoader.json(block.hash.string) + } + + "retrieve a block by height" in { + val block = posBlock + val response = GET(url(block.height.toString)) + + status(response) mustEqual OK + + val json = contentAsJson(response) + json mustEqual BlockLoader.json(block.hash.string) + } + } }