Skip to content

Commit

Permalink
feat: add average of transaction fees for last 24 hours with trend
Browse files Browse the repository at this point in the history
  • Loading branch information
yaboiishere committed Apr 26, 2024
1 parent 1cd473a commit 6d41661
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 15 deletions.
13 changes: 13 additions & 0 deletions lib/ae_mdw/node/db.ex
Expand Up @@ -152,6 +152,19 @@ defmodule AeMdw.Node.Db do
end
end

@spec get_tx_fee(binary()) :: non_neg_integer() | nil
def get_tx_fee(<<_pk::256>> = tx_hash) do
case :aec_db.find_tx_with_location(tx_hash) do
{_block_hash, signed_tx} ->
signed_tx
|> :aetx_sign.tx()
|> :aetx.fee()

:none ->
nil
end
end

@spec top_height_hash(boolean()) :: height_hash()
def top_height_hash(false = _the_very_top?) do
block = :aec_chain.top_key_block() |> ok!
Expand Down
37 changes: 32 additions & 5 deletions lib/ae_mdw/stats.ex
Expand Up @@ -16,6 +16,7 @@ defmodule AeMdw.Stats do
alias AeMdw.Node
alias AeMdw.Util
alias AeMdw.Validate
alias AeMdw.Node.Db, as: NodeDb

require Model

Expand Down Expand Up @@ -155,15 +156,18 @@ defmodule AeMdw.Stats do
State.get(state, Model.Stat, @tps_stat_key),
{:ok, Model.stat(payload: miners_count)} <-
State.get(state, Model.Stat, @miners_count_stat_key) do
{last_24hs_txs_count, trend} = last_24hs_txs_count_and_trend(state)
{{last_24hs_txs_count, trend}, {last_24hs_tx_fees_average, fees_trend}} =
last_24hs_txs_count_and_fee_with_trend(state)

{:ok,
%{
max_transactions_per_second: tps,
max_transactions_per_second_block_hash: Enc.encode(:key_block_hash, tps_block_hash),
miners_count: miners_count,
last_24hs_transactions: last_24hs_txs_count,
transactions_trend: trend
transactions_trend: trend,
last_24hs_average_transaction_fees: last_24hs_tx_fees_average,
fees_trend: fees_trend
}}
else
:not_found ->
Expand Down Expand Up @@ -562,7 +566,7 @@ defmodule AeMdw.Stats do
end
end

defp last_24hs_txs_count_and_trend(state) do
defp last_24hs_txs_count_and_fee_with_trend(state) do
time_24hs_ago = :aeu_time.now_in_msecs() - @seconds_per_day * 1_000

case State.next(state, Model.Time, {time_24hs_ago, -1}) do
Expand All @@ -576,10 +580,16 @@ defmodule AeMdw.Stats do
txs_count_48hs = tx_index_24hs_ago - tx_index_48hs_ago
trend = Float.round((txs_count_24hs - txs_count_48hs) / txs_count_24hs, 2)

{txs_count_24hs, trend}
average_tx_fees_24hs = average_tx_fees(state, tx_index_24hs_ago, last_tx_index)
average_tx_fees_48hs = average_tx_fees(state, tx_index_48hs_ago, tx_index_24hs_ago)

fee_trend =
Float.round((average_tx_fees_24hs - average_tx_fees_48hs) / average_tx_fees_24hs, 2)

{{txs_count_24hs, trend}, {average_tx_fees_24hs, fee_trend}}

:none ->
{0, 0}
{{0, 0}, {0, 0}}
end
end

Expand Down Expand Up @@ -615,4 +625,21 @@ defmodule AeMdw.Stats do
(year - @start_unix) * 12 + month - 1
end
end

defp average_tx_fees(state, start_txi, end_txi) do
txs_count = end_txi - start_txi + 1

if txs_count != 0 do
start_txi..end_txi
|> Enum.reduce(0, fn tx_index, acc ->
Model.tx(id: tx_hash) = State.fetch!(state, Model.Tx, tx_index)
fee = NodeDb.get_tx_fee(tx_hash)

acc + fee
end)
|> then(&(&1 / txs_count))
else
0
end
end
end
47 changes: 37 additions & 10 deletions test/ae_mdw_web/controllers/stats_controller_test.exs
@@ -1,5 +1,6 @@
defmodule AeMdwWeb.StatsControllerTest do
use AeMdwWeb.ConnCase, async: false
import Mock

alias :aeser_api_encoder, as: Enc
alias AeMdw.Db.Model
Expand Down Expand Up @@ -475,27 +476,53 @@ defmodule AeMdwWeb.StatsControllerTest do
end

describe "stats" do
test "it counts last 24hs transactions and 48hs comparison trend", %{conn: conn, store: store} do
test "it counts last 24hs transactions and 48hs comparison trend and gets average of fees with trend",
%{conn: conn, store: store} do
now = :aeu_time.now_in_msecs()
msecs_per_day = 3_600 * 24 * 1_000
delay = 10
delay = 500

last_24hs_start_txi = 8
last_txi = 21

store =
store
|> Store.put(Model.Tx, Model.tx(index: 21))
|> Store.put(Model.Time, Model.time(index: {now - msecs_per_day + delay, 7}))
|> Store.put(Model.Time, Model.time(index: {now - msecs_per_day * 2 + delay, 0}))
|> add_transactions(1, last_txi)
|> Store.put(
Model.Time,
Model.time(index: {now - msecs_per_day + delay, last_24hs_start_txi})
)
|> Store.put(Model.Time, Model.time(index: {now - msecs_per_day * 2 + delay, 1}))
|> Store.put(Model.Stat, Model.stat(index: :miners_count, payload: 2))
|> Store.put(Model.Stat, Model.stat(index: :max_tps, payload: {2, <<0::256>>}))

assert %{"last_24hs_transactions" => 14, "transactions_trend" => 0.5} =
conn
|> with_store(store)
|> get("/v2/stats")
|> json_response(200)
txis = last_24hs_start_txi..last_txi

fee_avg = Enum.sum(txis) / Enum.count(txis)

with_mocks([{AeMdw.Node.Db, [], get_tx_fee: fn <<i::256>> -> i end}]) do
assert %{
"last_24hs_transactions" => 13,
"transactions_trend" => 0.46,
"fees_trend" => 0.69,
"last_24hs_average_transaction_fees" => ^fee_avg
} =
conn
|> with_store(store)
|> get("/v2/stats")
|> json_response(200)
end
end
end

defp add_transactions(store, start_txi, end_txi) do
start_txi..end_txi
|> Enum.reduce({store, 1}, fn txi, {store, i} ->
{Store.put(store, Model.Tx, Model.tx(index: txi, id: <<i::256>>)), i + 1}
end)
|> elem(0)
end

defp network_time_interval do
start_time = DateTime.new!(Date.new!(1970, 1, 1), Time.new!(0, 0, 0))
end_time = DateTime.new!(Date.new!(1970, 2, 1), Time.new!(0, 0, 0))
Expand Down

0 comments on commit 6d41661

Please sign in to comment.