Skip to content

Commit

Permalink
Merge pull request #2862 from poanetwork/vb-coin-total-supply-from-db…
Browse files Browse the repository at this point in the history
…-api

Coin total supply from DB API endpoint
  • Loading branch information
vbaranov committed Nov 19, 2019
2 parents 0789ce8 + d81f094 commit 29faeff
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Current

### Features
- [#2862](https://github.com/poanetwork/blockscout/pull/2862) - Coin total supply from DB API endpoint
- [#2825](https://github.com/poanetwork/blockscout/pull/2825) - separate token transfers and transactions
- [#2787](https://github.com/poanetwork/blockscout/pull/2787) - async fetching of address counters
- [#2791](https://github.com/poanetwork/blockscout/pull/2791) - add ipc client
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
defmodule BlockScoutWeb.API.RPC.StatsController do
use BlockScoutWeb, :controller

use Explorer.Schema

alias Explorer.{Chain, ExchangeRates}
alias Explorer.Chain.Cache.AddressSum
alias Explorer.Chain.Wei

def tokensupply(conn, params) do
Expand All @@ -21,15 +24,21 @@ defmodule BlockScoutWeb.API.RPC.StatsController do
end
end

def ethsupply(conn, _params) do
def ethsupplyexchange(conn, _params) do
wei_total_supply =
Chain.total_supply()
|> Decimal.new()
|> Wei.from(:ether)
|> Wei.to(:wei)
|> Decimal.to_string()

render(conn, "ethsupply.json", total_supply: wei_total_supply)
render(conn, "ethsupplyexchange.json", total_supply: wei_total_supply)
end

def ethsupply(conn, _params) do
cached_wei_total_supply = AddressSum.get_sum()

render(conn, "ethsupply.json", total_supply: cached_wei_total_supply)
end

def ethprice(conn, _params) do
Expand Down
35 changes: 34 additions & 1 deletion apps/block_scout_web/lib/block_scout_web/etherscan.ex
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,12 @@ defmodule BlockScoutWeb.Etherscan do
"result" => "21265524714464"
}

@stats_ethsupplyexchange_example_value %{
"status" => "1",
"message" => "OK",
"result" => "101959776311500000000000000"
}

@stats_ethsupply_example_value %{
"status" => "1",
"message" => "OK",
Expand Down Expand Up @@ -1772,9 +1778,35 @@ defmodule BlockScoutWeb.Etherscan do
]
}

@stats_ethsupplyexchange_action %{
name: "ethsupplyexchange",
description: "Get total supply in Wei from exchange.",
required_params: [],
optional_params: [],
responses: [
%{
code: "200",
description: "successful operation",
example_value: Jason.encode!(@stats_ethsupplyexchange_example_value),
model: %{
name: "Result",
fields: %{
status: @status_type,
message: @message_type,
result: %{
type: "integer",
description: "The total supply.",
example: ~s("101959776311500000000000000")
}
}
}
}
]
}

@stats_ethsupply_action %{
name: "ethsupply",
description: "Get total supply in Wei.",
description: "Get total supply in Wei from DB.",
required_params: [],
optional_params: [],
responses: [
Expand Down Expand Up @@ -2302,6 +2334,7 @@ defmodule BlockScoutWeb.Etherscan do
name: "stats",
actions: [
@stats_tokensupply_action,
@stats_ethsupplyexchange_action,
@stats_ethsupply_action,
@stats_ethprice_action
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ defmodule BlockScoutWeb.API.RPC.StatsView do
RPCView.render("show.json", data: Decimal.to_string(token_supply))
end

def render("ethsupplyexchange.json", %{total_supply: total_supply}) do
RPCView.render("show.json", data: total_supply)
end

def render("ethsupply.json", %{total_supply: total_supply}) do
RPCView.render("show.json", data: total_supply)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,27 @@ defmodule BlockScoutWeb.API.RPC.StatsControllerTest do
end
end

describe "ethsupplyexchange" do
test "returns total supply from exchange", %{conn: conn} do
params = %{
"module" => "stats",
"action" => "ethsupplyexchange"
}

assert response =
conn
|> get("/api", params)
|> json_response(200)

assert response["result"] == "252460800000000000000000000"
assert response["status"] == "1"
assert response["message"] == "OK"
assert :ok = ExJsonSchema.Validator.validate(ethsupplyexchange_schema(), response)
end
end

describe "ethsupply" do
test "returns total supply", %{conn: conn} do
test "returns total supply from DB", %{conn: conn} do
params = %{
"module" => "stats",
"action" => "ethsupply"
Expand All @@ -97,7 +116,7 @@ defmodule BlockScoutWeb.API.RPC.StatsControllerTest do
|> get("/api", params)
|> json_response(200)

assert response["result"] == "252460800000000000000000000"
assert response["result"] == "6"
assert response["status"] == "1"
assert response["message"] == "OK"
assert :ok = ExJsonSchema.Validator.validate(ethsupply_schema(), response)
Expand Down Expand Up @@ -179,6 +198,12 @@ defmodule BlockScoutWeb.API.RPC.StatsControllerTest do
})
end

defp ethsupplyexchange_schema do
resolve_schema(%{
"type" => ["string", "null"]
})
end

defp ethprice_schema do
resolve_schema(%{
"type" => "object",
Expand Down
14 changes: 14 additions & 0 deletions apps/explorer/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ config :explorer, Explorer.Chain.Cache.BlockNumber,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))

address_sum_global_ttl =
"ADDRESS_SUM_CACHE_PERIOD"
|> System.get_env("")
|> Integer.parse()
|> case do
{integer, ""} -> :timer.seconds(integer)
_ -> :timer.minutes(60)
end

config :explorer, Explorer.Chain.Cache.AddressSum,
enabled: true,
ttl_check_interval: :timer.seconds(1),
global_ttl: address_sum_global_ttl

balances_update_interval =
if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do
case Integer.parse(System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do
Expand Down
2 changes: 2 additions & 0 deletions apps/explorer/lib/explorer/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Explorer.Application do

alias Explorer.Chain.Cache.{
Accounts,
AddressSum,
BlockCount,
BlockNumber,
Blocks,
Expand Down Expand Up @@ -46,6 +47,7 @@ defmodule Explorer.Application do
{Registry, keys: :duplicate, name: Registry.ChainEvents, id: Registry.ChainEvents},
{Admin.Recovery, [[], [name: Admin.Recovery]]},
TransactionCount,
AddressSum,
BlockCount,
Blocks,
NetVersion,
Expand Down
11 changes: 11 additions & 0 deletions apps/explorer/lib/explorer/chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,17 @@ defmodule Explorer.Chain do
Repo.one!(query)
end

@spec fetch_sum_coin_total_supply() :: non_neg_integer
def fetch_sum_coin_total_supply do
query =
from(
a0 in Address,
select: fragment("SUM(a0.fetched_coin_balance)")
)

Repo.one!(query) || 0
end

@doc """
The number of `t:Explorer.Chain.InternalTransaction.t/0`.
Expand Down
53 changes: 53 additions & 0 deletions apps/explorer/lib/explorer/chain/cache/address_sum.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule Explorer.Chain.Cache.AddressSum do
@moduledoc """
Cache for address sum.
"""

require Logger

use Explorer.Chain.MapCache,
name: :address_sum,
key: :sum,
key: :async_task,
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl],
callback: &async_task_on_deletion(&1)

alias Explorer.Chain

defp handle_fallback(:sum) do
# This will get the task PID if one exists and launch a new task if not
# See next `handle_fallback` definition
get_async_task()

{:return, nil}
end

defp handle_fallback(:async_task) do
# If this gets called it means an async task was requested, but none exists
# so a new one needs to be launched
{:ok, task} =
Task.start(fn ->
try do
result = Chain.fetch_sum_coin_total_supply()

set_sum(result)
rescue
e ->
Logger.debug([
"Coudn't update address sum test #{inspect(e)}"
])
end

set_async_task(nil)
end)

{:update, task}
end

# By setting this as a `callback` an async task will be started each time the
# `sum` expires (unless there is one already running)
defp async_task_on_deletion({:delete, _, :sum}), do: get_async_task()

defp async_task_on_deletion(_data), do: nil
end
56 changes: 56 additions & 0 deletions apps/explorer/test/explorer/chain/cache/address_sum_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
defmodule Explorer.Chain.Cache.AddressSumTest do
use Explorer.DataCase

alias Explorer.Chain.Cache.AddressSum

setup do
Supervisor.terminate_child(Explorer.Supervisor, AddressSum.child_id())
Supervisor.restart_child(Explorer.Supervisor, AddressSum.child_id())
:ok
end

test "returns default address sum" do
result = AddressSum.get_sum()

assert is_nil(result)
end

test "updates cache if initial value is zero" do
insert(:address, fetched_coin_balance: 1)
insert(:address, fetched_coin_balance: 2)
insert(:address, fetched_coin_balance: 3)

_result = AddressSum.get_sum()

Process.sleep(1000)

updated_value = Decimal.to_integer(AddressSum.get_sum())

assert updated_value == 6
end

test "does not update cache if cache period did not pass" do
insert(:address, fetched_coin_balance: 1)
insert(:address, fetched_coin_balance: 2)
insert(:address, fetched_coin_balance: 3)

_result = AddressSum.get_sum()

Process.sleep(1000)

updated_value = Decimal.to_integer(AddressSum.get_sum())

assert updated_value == 6

insert(:address, fetched_coin_balance: 4)
insert(:address, fetched_coin_balance: 5)

_updated_value = AddressSum.get_sum()

Process.sleep(1000)

updated_value = Decimal.to_integer(AddressSum.get_sum())

assert updated_value == 6
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule Explorer.Chain.Cache.BlockCountTest do
:ok
end

test "returns default transaction count" do
test "returns default block count" do
result = BlockCount.get_count()

assert is_nil(result)
Expand Down
14 changes: 14 additions & 0 deletions apps/explorer/test/explorer/chain_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,20 @@ defmodule Explorer.ChainTest do
end
end

describe "fetch_sum_coin_total_supply/0" do
test "fetches coin total supply" do
for index <- 0..4 do
insert(:address, fetched_coin_balance: index)
end

assert "10" = Decimal.to_string(Chain.fetch_sum_coin_total_supply())
end

test "fetches coin total supply when there are no blocks" do
assert 0 = Chain.fetch_sum_coin_total_supply()
end
end

describe "address_hash_to_token_transfers/2" do
test "returns just the token transfers related to the given contract address" do
contract_address =
Expand Down

0 comments on commit 29faeff

Please sign in to comment.