Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/codecov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Codecov

on:
push:
branches: [ master ]
pull_request:

jobs:
codecov:
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 (2025-11-17T15:57:55Z)
with:
fetch-depth: 0
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 (2025-12-04T03:00:25Z)
with:
distribution: temurin
java-version: 11
cache: sbt
- name: Setup sbt launcher
uses: sbt/setup-sbt@3e125ece5c3e5248e18da9ed8d2cce3d335ec8dd # v1.1.14 (2025-10-05T20:19:35Z)
- name: Test with coverage
run: sbt coverage test coverageReport
- name: Upload coverage to Codecov
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 (2025-09-04T14:36:56Z)
with:
name: codecov-explorer-backend
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Alephium explorer backend

[![codecov][codecov-badge]][codecov-link]

Alephium's explorer backend is an indexer that provides a RESTful API to query the Alephium blockchain.

It serves https://explorer.alephium.org/ as well as our wallets.
Expand Down Expand Up @@ -180,6 +182,8 @@ sbt test
[postgresql]: https://www.postgresql.org/
[sbt]: https://www.scala-sbt.org/
[bytea]: https://www.postgresql.org/docs/9.0/datatype-binary.html
[codecov-badge]: https://codecov.io/gh/alephium/explorer-backend/branch/master/graph/badge.svg
[codecov-link]: https://codecov.io/gh/alephium/explorer-backend

## Scaladoc

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import sttp.tapir.EndpointIO.Example
import org.alephium.api.EndpointsExamples
import org.alephium.api.model.{Address => ApiAddress, Amount, ValBool}
import org.alephium.explorer.api.model._
import org.alephium.explorer.persistence.queries.ExplainResult
import org.alephium.protocol.{ALPH, PublicKey}
import org.alephium.protocol.mining.HashRate
import org.alephium.protocol.model.{Address, BlockHash, ContractId, GroupIndex, TokenId}
Expand Down Expand Up @@ -337,23 +336,6 @@ object EndpointExamples extends EndpointsExamples {
value = 60
)

private val explainResult =
ExplainResult(
queryName = "queryName",
queryInput = "Pagination(0,20,false)",
explain = Vector(
"Seq Scan on table_name (cost=0.00..850.88 rows=20088 width=198) (actual time=0.007..4.358 rows=20088 loops=1)",
" Filter: table_column",
"Planning Time: 0.694 ms",
"Execution Time: 5.432 ms"
),
messages = Array(
"Used table_column_idx = false",
"Used table_pk = true"
),
passed = true
)

private val logbackValue =
LogbackValue(
name = "org.test",
Expand Down Expand Up @@ -456,9 +438,6 @@ object EndpointExamples extends EndpointsExamples {
implicit val perChainDurationExample: List[Example[ArraySeq[PerChainDuration]]] =
simpleExample(ArraySeq(perChainDuration, perChainDuration))

implicit val explainResultExample: List[Example[ArraySeq[ExplainResult]]] =
simpleExample(ArraySeq(explainResult))

implicit val logbackValueExample: List[Example[ArraySeq[LogbackValue]]] =
simpleExample(ArraySeq(logbackValue))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import sttp.tapir.generic.auto._
import org.alephium.api.Endpoints.jsonBody
import org.alephium.explorer.api.EndpointExamples._
import org.alephium.explorer.api.model.LogbackValue
import org.alephium.explorer.persistence.queries.ExplainResult

// scalastyle:off magic.number
trait UtilsEndpoints extends BaseEndpoint with QueryParams {
Expand All @@ -29,12 +28,6 @@ trait UtilsEndpoints extends BaseEndpoint with QueryParams {
.in("sanity-check")
.summary("Perform a sanity check")

val indexCheck: BaseEndpoint[Unit, ArraySeq[ExplainResult]] =
utilsEndpoint.get
.in("index-check")
.out(jsonBody[ArraySeq[ExplainResult]])
.summary("Perform index check")

val changeGlobalLogLevel: BaseEndpoint[String, Unit] =
utilsEndpoint.put
.in("update-global-loglevel")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,4 @@ final case class InputEntity(
outputRefAmount: Option[U256],
outputRefTokens: Option[ArraySeq[Token]], // None if empty list
contractInput: Boolean
) extends InputEntityLike {

/** @return All hash types associated with this [[InputEntity]] */
def hashes(): (TransactionId, BlockHash) =
(txHash, blockHash)
}
) extends InputEntityLike
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.alephium.explorer.persistence.queries.TransactionQueries._
import org.alephium.explorer.persistence.schema._
import org.alephium.explorer.persistence.schema.CustomGetResult._
import org.alephium.explorer.persistence.schema.CustomSetParameter._
import org.alephium.explorer.util.SlickExplainUtil._
import org.alephium.explorer.util.SlickUtil._
import org.alephium.protocol.model.{BlockHash, GroupIndex, TransactionId}
import org.alephium.util.TimeStamp
Expand Down Expand Up @@ -66,17 +65,6 @@ object BlockQueries extends StrictLogging {
@SuppressWarnings(Array("org.wartremover.warts.PublicInference"))
val mainChainQuery = BlockHeaderSchema.table.filter(_.mainChain)

def explainMainChainQuery()(implicit ec: ExecutionContext): DBActionR[ExplainResult] =
mainChainQuery.result.explainAnalyze() map { explain =>
ExplainResult(
queryName = "mainChainQuery",
queryInput = "Unit",
explain = explain,
messages = Iterable.empty,
passed = explain.mkString contains "block_headers_main_chain_idx"
)
}

def getBlockEntryLiteAction(
hash: BlockHash
): DBActionR[Option[BlockEntryLite]] =
Expand Down Expand Up @@ -210,19 +198,6 @@ object BlockQueries extends StrictLogging {
listMainChainHeadersWithTxnNumberBuilder(pagination)
.asASE[BlockEntryLite](blockEntryListGetResult)

def explainListMainChainHeadersWithTxnNumber(
pagination: Pagination.Reversible
)(implicit ec: ExecutionContext): DBActionR[ExplainResult] =
listMainChainHeadersWithTxnNumberBuilder(pagination).explainAnalyze() map { explain =>
ExplainResult(
queryName = "listMainChainHeadersWithTxnNumber",
queryInput = pagination.toString,
explain = explain,
messages = Iterable.empty,
passed = explain.mkString contains "block_headers_full_index"
)
}

def listMainChainHeadersWithTxnNumberBuilder(
pagination: Pagination.Reversible
): SQLActionBuilder = {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import org.alephium.explorer.persistence.model._
import org.alephium.explorer.persistence.queries.result.{InputFromTxQR, InputQR}
import org.alephium.explorer.persistence.schema.CustomGetResult._
import org.alephium.explorer.persistence.schema.CustomSetParameter._
import org.alephium.explorer.util.SlickExplainUtil._
import org.alephium.explorer.util.SlickUtil._
import org.alephium.protocol.model.{BlockHash, TransactionId}

Expand Down Expand Up @@ -150,26 +149,4 @@ object InputQueries {
LIMIT 1
""".asAS[ByteString].headOrNone
}

/** Runs explain on query `inputsFromTxs` and checks the index `inputs_tx_hash_block_hash_idx` is
* being used
*/
def explainInputsFromTxs(
hashes: ArraySeq[(TransactionId, BlockHash)]
)(implicit ec: ExecutionContext): DBActionR[ExplainResult] = {
val queryName = "inputsFromTxs"
if (hashes.isEmpty) {
DBIOAction.successful(ExplainResult.emptyInput(queryName))
} else {
inputsFromTxsBuilder(hashes).explainAnalyze() map { explain =>
ExplainResult(
queryName = queryName,
queryInput = hashes.toString(),
explain = explain,
messages = Iterable.empty,
passed = explain.exists(_.contains("inputs_tx_hash_block_hash_idx"))
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import org.alephium.explorer.persistence.model._
import org.alephium.explorer.persistence.queries.result.{OutputFromTxQR, OutputQR}
import org.alephium.explorer.persistence.schema.CustomGetResult._
import org.alephium.explorer.persistence.schema.CustomSetParameter._
import org.alephium.explorer.util.SlickExplainUtil._
import org.alephium.explorer.util.SlickUtil._
import org.alephium.protocol.Hash
import org.alephium.protocol.model.{BlockHash, TransactionId}
Expand Down Expand Up @@ -390,39 +389,6 @@ object OutputQueries {
""".asASE[OutputEntity](outputGetResult)
}

/** Checks that [[getTxnHash]] uses both indexes for the given key */
def explainGetTxnHash(
key: Option[Hash]
)(implicit ec: ExecutionContext): DBActionR[ExplainResult] = {
val queryName = "getTxnHashBuilder"

key match {
case Some(key) =>
getTxnHashBuilder(key).explainAnalyze() map { explain =>
val explainString = explain.mkString
val outputs_pk_used = explainString contains "outputs_pk"
val outputs_main_chain_idx_used = explainString contains "outputs_main_chain_idx"
val passed = outputs_pk_used && outputs_main_chain_idx_used
val message =
ArraySeq(
s"Used outputs_main_chain_idx = $outputs_main_chain_idx_used",
s"Used outputs_pk = $outputs_pk_used"
)

ExplainResult(
queryName = queryName,
queryInput = key.toString(),
explain = explain,
messages = message,
passed = passed
)
}

case None =>
DBIOAction.successful(ExplainResult.emptyInput(queryName))
}
}

def getTxnHash(key: Hash): DBActionSR[TransactionId] =
getTxnHashBuilder(key).asAS[TransactionId]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ final case class TxByTokenQR(
conflicted: Option[Boolean]
) {

def hashes(): (TransactionId, BlockHash) =
(txHash, blockHash)

def toTxByAddressQR: TxByAddressQR = TxByAddressQR(
txHash,
blockHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.alephium.api.model.{Address => ApiAddress}
import org.alephium.api.model.Val
import org.alephium.explorer.api.Json._
import org.alephium.explorer.api.model._
import org.alephium.explorer.persistence.model.{GrouplessAddress, InterfaceIdEntity, OutputEntity}
import org.alephium.explorer.persistence.model.{GrouplessAddress, OutputEntity}
import org.alephium.json.Json._
import org.alephium.protocol.Hash
import org.alephium.protocol.model._
Expand All @@ -41,17 +41,6 @@ object CustomSetParameter {
params setInt input.value
}

implicit object GroupIndexOptionSetParameter extends SetParameter[Option[GroupIndex]] {
override def apply(option: Option[GroupIndex], params: PositionedParameters): Unit =
option match {
case Some(group) =>
GroupIndexSetParameter(group, params)

case None =>
params setIntOption None
}
}

implicit object IntervalTypeSetParameter extends SetParameter[IntervalType] {
override def apply(input: IntervalType, params: PositionedParameters): Unit =
params setInt input.value
Expand All @@ -62,11 +51,6 @@ object CustomSetParameter {
params setString input.id
}

implicit object InterfaceIdSetParameter extends SetParameter[InterfaceIdEntity] {
override def apply(input: InterfaceIdEntity, params: PositionedParameters): Unit =
params setString input.id
}

implicit object OutputTypeSetParameter extends SetParameter[OutputEntity.OutputType] {
override def apply(input: OutputEntity.OutputType, params: PositionedParameters): Unit =
params setInt input.value
Expand Down Expand Up @@ -120,17 +104,6 @@ object CustomSetParameter {
}
}

implicit object OptionApiAddressSetParameter extends SetParameter[Option[ApiAddress]] {
override def apply(option: Option[ApiAddress], params: PositionedParameters): Unit =
option match {
case Some(address) =>
ApiAddressSetParameter(address, params)

case None =>
params setStringOption None
}
}

implicit object OptionGrouplessAddressSetParameter
extends SetParameter[Option[GrouplessAddress]] {
override def apply(option: Option[GrouplessAddress], params: PositionedParameters): Unit =
Expand All @@ -143,11 +116,6 @@ object CustomSetParameter {
}
}

implicit object ArrayByteStringSetParameter extends SetParameter[Array[Byte]] {
override def apply(input: Array[Byte], params: PositionedParameters): Unit =
params setBytes input
}

implicit object ByteStringSetParameter extends SetParameter[ByteString] {
override def apply(input: ByteString, params: PositionedParameters): Unit =
params setBytes input.toArray
Expand Down
Loading
Loading