diff --git a/server/app/com/xsn/explorer/services/BlockService.scala b/server/app/com/xsn/explorer/services/BlockService.scala index 6812651..3748a1d 100644 --- a/server/app/com/xsn/explorer/services/BlockService.scala +++ b/server/app/com/xsn/explorer/services/BlockService.scala @@ -7,16 +7,17 @@ import com.alexitc.playsonify.models.pagination.{Limit, Offset, PaginatedQuery} import com.alexitc.playsonify.validators.PaginatedQueryValidator import com.xsn.explorer.cache.BlockHeaderCache import com.xsn.explorer.data.async.BlockFutureDataHandler -import com.xsn.explorer.errors.{BlockRewardsNotFoundError, BlockhashFormatError} +import com.xsn.explorer.errors.BlockRewardsNotFoundError import com.xsn.explorer.models._ import com.xsn.explorer.models.persisted.BlockHeader import com.xsn.explorer.models.rpc.{Block, TransactionVIN} import com.xsn.explorer.models.values.{Blockhash, Height} import com.xsn.explorer.parsers.OrderingConditionParser import com.xsn.explorer.services.logic.{BlockLogic, TransactionLogic} +import com.xsn.explorer.services.validators.BlockhashValidator import com.xsn.explorer.util.Extensions.FutureOrExt import javax.inject.Inject -import org.scalactic.{Bad, Good, One, Or} +import org.scalactic.{Bad, Good} import play.api.libs.json.{JsValue, Writes} import scala.concurrent.{ExecutionContext, Future} @@ -25,6 +26,7 @@ class BlockService @Inject() ( xsnService: XSNService, blockDataHandler: BlockFutureDataHandler, paginatedQueryValidator: PaginatedQueryValidator, + blockhashValidator: BlockhashValidator, blockLogic: BlockLogic, transactionLogic: TransactionLogic, orderingConditionParser: OrderingConditionParser, @@ -40,13 +42,10 @@ class BlockService @Inject() ( implicit writes: Writes[BlockHeader]): FutureApplicationResult[JsValue] = { val result = for { - lastSeenHash <- { - lastSeenHashString - .map(Blockhash.from) - .map { txid => Or.from(txid, One(BlockhashFormatError)).map(Option.apply) } - .getOrElse(Good(Option.empty)) - .toFutureOr - } + lastSeenHash <- lastSeenHashString + .map { string => blockhashValidator.validate(string).map(Option.apply) } + .getOrElse(Good(None)) + .toFutureOr _ <- paginatedQueryValidator.validate(PaginatedQuery(Offset(0), limit), maxHeadersPerQuery).toFutureOr orderingCondition <- orderingConditionParser.parseReuslt(orderingConditionString).toFutureOr @@ -75,10 +74,7 @@ class BlockService @Inject() ( def getRawBlock(blockhashString: String): FutureApplicationResult[JsValue] = { val result = for { - blockhash <- blockLogic - .getBlockhash(blockhashString) - .toFutureOr - + blockhash <- blockhashValidator.validate(blockhashString).toFutureOr block <- xsnService.getRawBlock(blockhash).toFutureOr } yield block @@ -96,10 +92,7 @@ class BlockService @Inject() ( def getDetails(blockhashString: String): FutureApplicationResult[BlockDetails] = { val result = for { - blockhash <- blockLogic - .getBlockhash(blockhashString) - .toFutureOr - + blockhash <- blockhashValidator.validate(blockhashString).toFutureOr details <- getDetailsPrivate(blockhash).toFutureOr } yield details diff --git a/server/app/com/xsn/explorer/services/logic/BlockLogic.scala b/server/app/com/xsn/explorer/services/logic/BlockLogic.scala index 1289c60..449c0bd 100644 --- a/server/app/com/xsn/explorer/services/logic/BlockLogic.scala +++ b/server/app/com/xsn/explorer/services/logic/BlockLogic.scala @@ -1,19 +1,14 @@ package com.xsn.explorer.services.logic import com.alexitc.playsonify.core.ApplicationResult -import com.xsn.explorer.errors.{BlockNotFoundError, BlockhashFormatError, TransactionNotFoundError} +import com.xsn.explorer.errors.{BlockNotFoundError, TransactionNotFoundError} import com.xsn.explorer.models._ import com.xsn.explorer.models.rpc.{Block, Transaction} -import com.xsn.explorer.models.values.{Address, Blockhash, TransactionId} +import com.xsn.explorer.models.values.{Address, TransactionId} import org.scalactic.{Bad, Good, One, Or} class BlockLogic { - def getBlockhash(string: String): ApplicationResult[Blockhash] = { - val maybe = Blockhash.from(string) - Or.from(maybe, One(BlockhashFormatError)) - } - def getPoWTransactionId(block: Block): ApplicationResult[TransactionId] = { val maybe = block.transactions.headOption diff --git a/server/app/com/xsn/explorer/services/validators/BlockhashValidator.scala b/server/app/com/xsn/explorer/services/validators/BlockhashValidator.scala new file mode 100644 index 0000000..d957a3a --- /dev/null +++ b/server/app/com/xsn/explorer/services/validators/BlockhashValidator.scala @@ -0,0 +1,12 @@ +package com.xsn.explorer.services.validators + +import com.alexitc.playsonify.core.ApplicationResult +import com.xsn.explorer.errors.BlockhashFormatError +import com.xsn.explorer.models.values.Blockhash + +class BlockhashValidator { + + def validate(string: String): ApplicationResult[Blockhash] = { + optional(string, BlockhashFormatError)(Blockhash.from) + } +} diff --git a/server/app/com/xsn/explorer/services/validators/package.scala b/server/app/com/xsn/explorer/services/validators/package.scala new file mode 100644 index 0000000..1af28ee --- /dev/null +++ b/server/app/com/xsn/explorer/services/validators/package.scala @@ -0,0 +1,13 @@ +package com.xsn.explorer.services + +import com.alexitc.playsonify.core.ApplicationResult +import com.alexitc.playsonify.models.ApplicationError +import org.scalactic.{One, Or} + +package object validators { + + def optional[T](string: String, error: ApplicationError)(builder: String => Option[T]): ApplicationResult[T] = { + val maybe = builder(string) + Or.from(maybe, One(error)) + } +} diff --git a/server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala b/server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala index 880f4af..8f54dc8 100644 --- a/server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala +++ b/server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala @@ -13,7 +13,7 @@ import com.xsn.explorer.models.rpc.Block import com.xsn.explorer.models.values.{Blockhash, Height} import com.xsn.explorer.parsers.{OrderingConditionParser, TransactionOrderingParser} import com.xsn.explorer.services.logic.{BlockLogic, TransactionLogic} -import com.xsn.explorer.services.validators.AddressValidator +import com.xsn.explorer.services.validators.{AddressValidator, BlockhashValidator} import org.scalactic.{Bad, Good, One, Or} import org.scalatest.BeforeAndAfter import org.scalatest.concurrent.ScalaFutures @@ -223,6 +223,7 @@ class LedgerSynchronizerServiceSpec extends PostgresDataHandlerSpec with BeforeA xsnService, new BlockFutureDataHandler(blockDataHandler)(Executors.databaseEC), new PaginatedQueryValidator, + new BlockhashValidator, new BlockLogic, new TransactionLogic, new OrderingConditionParser,