diff --git a/server/app/com/xsn/explorer/data/anorm/dao/StatisticsPostgresDAO.scala b/server/app/com/xsn/explorer/data/anorm/dao/StatisticsPostgresDAO.scala index 5db85fa..ea8d3ae 100644 --- a/server/app/com/xsn/explorer/data/anorm/dao/StatisticsPostgresDAO.scala +++ b/server/app/com/xsn/explorer/data/anorm/dao/StatisticsPostgresDAO.scala @@ -8,18 +8,30 @@ import com.xsn.explorer.models.Statistics class StatisticsPostgresDAO { + import StatisticsPostgresDAO._ + def getStatistics(implicit conn: Connection): Statistics = { SQL( - """ + s""" |SELECT - | (SELECT SUM(received - spent) FROM balances) AS total_supply, + | ( + | SELECT SUM(received - spent) FROM balances + | WHERE address <> '$BurnAddress' + | ) AS total_supply, | ( | SELECT SUM(received - spent) FROM balances | WHERE address NOT IN (SELECT address FROM hidden_addresses) | ) AS circulating_supply, | (SELECT COUNT(*) FROM transactions) AS transactions, - | (SELECT MAX(height) FROM blocks) AS blocks + | (SELECT COALESCE(MAX(height), 0) FROM blocks) AS blocks """.stripMargin ).as(StatisticsParsers.parseStatistics.single) } } + +object StatisticsPostgresDAO { + /** + * We need to exclude the burn address from the total supply. + */ + val BurnAddress = "XmPe9BHRsmZeThtYF34YYjdnrjmcAUn8bC" +} diff --git a/server/test/com/xsn/explorer/data/StatisticsPostgresDataHandlerSpec.scala b/server/test/com/xsn/explorer/data/StatisticsPostgresDataHandlerSpec.scala new file mode 100644 index 0000000..3d69c0e --- /dev/null +++ b/server/test/com/xsn/explorer/data/StatisticsPostgresDataHandlerSpec.scala @@ -0,0 +1,53 @@ +package com.xsn.explorer.data + +import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, StatisticsPostgresDAO} +import com.xsn.explorer.data.anorm.interpreters.FieldOrderingSQLInterpreter +import com.xsn.explorer.data.anorm.{BalancePostgresDataHandler, StatisticsPostgresDataHandler} +import com.xsn.explorer.data.common.PostgresDataHandlerSpec +import com.xsn.explorer.helpers.DataHelper +import com.xsn.explorer.models.{Address, Balance} + +class StatisticsPostgresDataHandlerSpec extends PostgresDataHandlerSpec { + + lazy val dataHandler = new StatisticsPostgresDataHandler(database, new StatisticsPostgresDAO) + lazy val balanceDataHandler = new BalancePostgresDataHandler(database, new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) + + "getStatistics" should { + "succeed even if there is no data" in { + val result = dataHandler.getStatistics() + result.isGood mustEqual true + } + + "exclude hidden_addresses from the circulating supply" in { + val hiddenAddress = DataHelper.createAddress("XfAATXtkRgCdMTrj2fxHvLsKLLmqAjhEAt") + val circulatingSupply = dataHandler.getStatistics().get.circulatingSupply + + database.withConnection { implicit conn => + _root_.anorm.SQL( + s""" + |INSERT INTO hidden_addresses (address) + |VALUES ('${hiddenAddress.string}') + """.stripMargin + ).execute() + } + + val balance = Balance(hiddenAddress, received = BigDecimal(1000), spent = BigDecimal(500)) + balanceDataHandler.upsert(balance).isGood mustEqual true + + val result = dataHandler.getStatistics().get + result.circulatingSupply mustEqual circulatingSupply + } + + "exclude the burn address from the total supply" in { + val burnAddress = Address.from(StatisticsPostgresDAO.BurnAddress).get + + val totalSupply = dataHandler.getStatistics().get.totalSupply + + val balance = Balance(burnAddress, received = BigDecimal(1000), spent = BigDecimal(500)) + balanceDataHandler.upsert(balance).isGood mustEqual true + + val result = dataHandler.getStatistics().get + result.totalSupply mustEqual totalSupply + } + } +}