Fixed formatting

pull/2404/head
slightlycyborg 5 years ago
parent 51ee7edcc7
commit e9ac019d70
  1. 59
      apps/block_scout_web/assets/js/lib/history_chart.js
  2. 114
      apps/block_scout_web/assets/js/lib/transaction_history_chart.js
  3. 7
      apps/block_scout_web/assets/js/pages/chain.js
  4. 11
      apps/block_scout_web/lib/block_scout_web/controllers/chain/transaction_history_chart_controller.ex
  5. 13
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  6. 9
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  7. 39
      apps/explorer/lib/explorer/chain/transaction/history/historian.ex
  8. 9
      apps/explorer/lib/explorer/chain/transaction/history/transaction_stats.ex
  9. 8
      apps/explorer/lib/explorer/history/historian.ex
  10. 10
      apps/explorer/lib/explorer/history/process.ex
  11. 14
      apps/explorer/lib/explorer/market/history/historian.ex
  12. 32
      apps/explorer/test/explorer/chain/transaction/history/historian_test.exs
  13. 10
      apps/explorer/test/explorer/chain/transaction/history/transaction_stats_test.exs
  14. 8
      apps/explorer/test/explorer/history/process_test.exs

@ -105,12 +105,11 @@ function getMarketCapData (marketHistoryData, availableSupply) {
class MarketHistoryChart {
constructor (el, availableSupply, marketHistoryData, dataConfig) {
var axes = config.options.scales.yAxes.reduce(function(solution, elem){
var axes = config.options.scales.yAxes.reduce(function (solution, elem) {
solution[elem.id] = elem
return solution
},
{})
{})
this.price = {
label: window.localized['Price'],
@ -122,9 +121,9 @@ class MarketHistoryChart {
borderColor: sassVariables.dashboardLineColorPrice,
lineTension: 0
}
if (dataConfig.market == undefined || dataConfig.market.indexOf("price") == -1){
if (dataConfig.market === undefined || dataConfig.market.indexOf('price') === -1) {
this.price.hidden = true
axes["price"].display = false
axes['price'].display = false
}
this.marketCap = {
@ -137,9 +136,9 @@ class MarketHistoryChart {
borderColor: sassVariables.dashboardLineColorMarket,
lineTension: 0
}
if (dataConfig.market == undefined || dataConfig.market.indexOf("market_cap") == -1){
if (dataConfig.market === undefined || dataConfig.market.indexOf('market_cap') === -1) {
this.marketCap.hidden = true
axes["marketCap"].display = false
axes['marketCap'].display = false
}
this.numTransactions = {
@ -150,15 +149,14 @@ class MarketHistoryChart {
pointRadius: 0,
backgroundColor: sassVariables.dashboardLineColorMarket,
borderColor: sassVariables.dashboardLineColorTransactions,
lineTension: 0,
lineTension: 0
}
if (dataConfig.transactions == undefined || dataConfig.transactions.indexOf("transactions_per_day") == -1){
if (dataConfig.transactions === undefined || dataConfig.transactions.indexOf('transactions_per_day') === -1) {
this.numTransactions.hidden = true
axes["numTransactions"].display = false
axes['numTransactions'].display = false
}
this.availableSupply = availableSupply
//TODO: This is where we dynamically append datasets
config.data.datasets = [this.price, this.marketCap, this.numTransactions]
this.chart = new Chart(el, config)
}
@ -173,9 +171,9 @@ class MarketHistoryChart {
}
this.chart.update()
}
updateTransactionHistory (transaction_history) {
this.numTransactions.data = transaction_history.map(dataPoint => {
return {x:dataPoint.date, y:dataPoint.number_of_transactions}
updateTransactionHistory (transactionHistory) {
this.numTransactions.data = transactionHistory.map(dataPoint => {
return {x: dataPoint.date, y: dataPoint.number_of_transactions}
})
this.chart.update()
}
@ -188,22 +186,22 @@ export function createMarketHistoryChart (el) {
const $chartLoading = $('[data-chart-loading-message]')
const $chartError = $('[data-chart-error-message]')
const chart = new MarketHistoryChart(el, 0, [], dataConfig)
Object.keys(dataPaths).forEach(function(history_source){
$.getJSON(dataPaths[history_source], {type: 'JSON'})
Object.keys(dataPaths).forEach(function (historySource) {
$.getJSON(dataPaths[historySource], {type: 'JSON'})
.done(data => {
switch(history_source){
case "market":
const availableSupply = JSON.parse(data.supply_data)
const marketHistoryData = humps.camelizeKeys(JSON.parse(data.history_data))
$(el).show()
chart.updateMarketHistory(availableSupply, marketHistoryData)
break;
case "transaction":
const transaction_history = JSON.parse(data.history_data)
switch (historySource) {
case 'market':
const availableSupply = JSON.parse(data.supply_data)
const marketHistoryData = humps.camelizeKeys(JSON.parse(data.history_data))
$(el).show()
chart.updateMarketHistory(availableSupply, marketHistoryData)
break
case 'transaction':
const transactionHistory = JSON.parse(data.history_data)
$(el).show()
chart.updateTransactionHistory(transaction_history)
break;
$(el).show()
chart.updateTransactionHistory(transactionHistory)
break
}
})
.fail(() => {
@ -211,8 +209,9 @@ export function createMarketHistoryChart (el) {
})
.always(() => {
$chartLoading.hide()
})})
return chart;
})
})
return chart
}
$('[data-chart-error-message]').on('click', _event => {

@ -1,114 +0,0 @@
import $ from 'jquery'
import Chart from 'chart.js'
import humps from 'humps'
import numeral from 'numeral'
import { formatUsdValue } from '../lib/currency'
import sassVariables from '../../css/app.scss'
const config = {
type: 'line',
responsive: true,
data: {
datasets: []
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: false,
drawBorder: false
},
type: 'time',
time: {
unit: 'day',
stepSize: 14
},
ticks: {
fontColor: sassVariables.dashboardBannerChartAxisFontColor
}
}],
yAxes: [{
id: 'num_transactions',
gridLines: {
display: false,
drawBorder: false
},
ticks: {
beginAtZero: true,
callback: (value, index, values) => `$${numeral(value).format('0,0.00')}`,
maxTicksLimit: 4,
fontColor: sassVariables.dashboardBannerChartAxisFontColor
}
}]
},
tooltips: {
mode: 'index',
intersect: false,
callbacks: {
label: ({datasetIndex, yLabel}, {datasets}) => {
const label = datasets[datasetIndex].label
if (datasets[datasetIndex].yAxisID === 'num_transactions') {
return `${label}: ${formatUsdValue(yLabel)}`
} else {
return yLabel
}
}
}
}
}
}
function transformData (marketHistoryData) {
return marketHistoryData.map(
({ date, num_transactions }) => ({x: date, y: num_transactions}))
}
class TransactionHistoryChart {
constructor (el, transactionHistoryData) {
this.num_transactions = {
label: window.localized['Price'],
yAxisID: 'num_transactions',
data: transformData(transactionHistoryData),
fill: false,
pointRadius: 0,
backgroundColor: sassVariables.dashboardLineColorPrice,
borderColor: sassVariables.dashboardLineColorPrice,
lineTension: 0
}
config.data.datasets = [this.num_transactions]
this.chart = new Chart(el, config)
}
update (transactionHistoryData) {
this.num_transactions.data = transformData(TransactionHistoryData)
this.chart.update()
}
}
export function createTransactionHistoryChart (el) {
const dataPath = el.dataset.transaction_history_chart_path
const $chartLoading = $('[data-chart-loading-message]')
const $chartError = $('[data-chart-error-message]')
const chart = new TransactionHistoryChart(el, 0, [])
$.getJSON(dataPath, {type: 'JSON'})
.done(data => {
const transactionStats = JSON.parse(data.history_data)
$(el).show()
chart.update(transactionStats)
})
.fail(() => {
$chartError.show()
})
.always(() => {
$chartLoading.hide()
})
return chart
}
$('[data-chart-error-message]').on('click', _event => {
$('[data-chart-loading-message]').show()
$('[data-chart-error-message]').hide()
createTransactionHistoryChart($('[data-chart="marketHistoryChart"]')[0])
})

@ -1,3 +1,4 @@
/* global _ */
import $ from 'jquery'
import omit from 'lodash/omit'
import first from 'lodash/first'
@ -107,9 +108,9 @@ function baseReducer (state = initialState, action) {
})
}
}
case 'RECIEVED_UPDATED_TRANSACTION_STATS':{
case 'RECIEVED_UPDATED_TRANSACTION_STATS': {
return Object.assign({}, state, {
transactionStats: action.msg.stats,
transactionStats: action.msg.stats
})
}
case 'START_TRANSACTIONS_FETCH':
@ -154,7 +155,7 @@ const elements = {
if (chart && !(oldState.availableSupply === state.availableSupply && oldState.marketHistoryData === state.marketHistoryData) && state.availableSupply) {
chart.updateMarketHistory(state.availableSupply, state.marketHistoryData)
}
if (chart && !(_.isEqual(oldState.transactionStats, state.transactionStats))){
if (chart && !(_.isEqual(oldState.transactionStats, state.transactionStats))) {
chart.updateTransactionHistory(state.transactionStats)
}
}

@ -5,17 +5,19 @@ defmodule BlockScoutWeb.Chain.TransactionHistoryChartController do
def show(conn, _params) do
with true <- ajax?(conn) do
[{:history_size, history_size}] = Application.get_env(:block_scout_web, __MODULE__, 30)
[{:history_size, history_size}] = Application.get_env(:block_scout_web, __MODULE__, 30)
latest = Date.utc_today()
earliest = Date.add(latest, -1 * history_size)
transaction_history_data = TransactionStats.by_date_range(earliest, latest)
date_range = TransactionStats.by_date_range(earliest, latest)
transaction_history_data = date_range
|> extract_history
|> encode_transaction_history_data
json(conn, %{
history_data: transaction_history_data,
history_data: transaction_history_data
})
else
_ -> unprocessable_entity(conn)
@ -24,7 +26,8 @@ defmodule BlockScoutWeb.Chain.TransactionHistoryChartController do
defp extract_history(db_results) do
Enum.map(db_results, fn row ->
%{date: row.date, number_of_transactions: row.number_of_transactions} end)
%{date: row.date, number_of_transactions: row.number_of_transactions}
end)
end
defp encode_transaction_history_data(transaction_history_data) do

@ -4,8 +4,8 @@ defmodule BlockScoutWeb.ChainController do
alias BlockScoutWeb.ChainView
alias Explorer.{Chain, PagingOptions, Repo}
alias Explorer.Chain.{Address, Block, Transaction}
alias Explorer.Chain.Transaction.History.TransactionStats
alias Explorer.Chain.Supply.RSK
alias Explorer.Chain.Transaction.History.TransactionStats
alias Explorer.Counters.AverageBlockTime
alias Explorer.ExchangeRates.Token
alias Explorer.Market
@ -15,7 +15,6 @@ defmodule BlockScoutWeb.ChainController do
transaction_estimated_count = Chain.transaction_estimated_count()
block_count = Chain.block_estimated_count()
market_cap_calculation =
case Application.get_env(:explorer, :supply) do
RSK ->
@ -29,8 +28,10 @@ defmodule BlockScoutWeb.ChainController do
transaction_stats = get_transaction_stats()
chart_data_paths = %{market: market_history_chart_path(conn, :show),
transaction: transaction_history_chart_path(conn, :show)}
chart_data_paths = %{
market: market_history_chart_path(conn, :show),
transaction: transaction_history_chart_path(conn, :show)
}
chart_config = Application.get_env(:block_scout_web, :chart_config, %{})
@ -51,14 +52,14 @@ defmodule BlockScoutWeb.ChainController do
)
end
def get_transaction_stats() do
def get_transaction_stats do
stats_scale = date_range(1)
TransactionStats.by_date_range(stats_scale.earliest, stats_scale.latest)
end
def date_range(num_days) do
today = Date.utc_today()
x_days_back = Date.add(today, -1*(num_days-1))
x_days_back = Date.add(today, -1 * (num_days - 1))
%{earliest: x_days_back, latest: today}
end

@ -122,11 +122,14 @@ defmodule BlockScoutWeb.Notifier do
def handle_event({:chain_event, :transaction_stats}) do
today = Date.utc_today()
[{:history_size, history_size}] = Application.get_env(:block_scout_web, BlockScoutWeb.Chain.TransactionHistoryChartController, 30)
[{:history_size, history_size}] =
Application.get_env(:block_scout_web, BlockScoutWeb.Chain.TransactionHistoryChartController, 30)
x_days_back = Date.add(today, -1 * history_size)
stats = TransactionStats.by_date_range(x_days_back, today)
|> Enum.map(fn item -> Map.drop(item, [:__meta__]) end)
date_range = TransactionStats.by_date_range(x_days_back, today)
stats = Enum.map(date_range, fn item -> Map.drop(item, [:__meta__]) end)
Endpoint.broadcast("transactions:stats", "update", %{stats: stats})
end

@ -1,44 +1,49 @@
defmodule Explorer.Chain.Transaction.History.Historian do
@moduledoc """
Implements behaviour Historian which will compile TransactionStats from Block/Transaction data and then save the TransactionStats into the database for later retrevial.
"""
use Explorer.History.Historian
alias Explorer.Chain.{Block, Transaction}
alias Explorer.Chain.Events.Publisher
alias Explorer.Chain.Transaction.History.TransactionStats
alias Explorer.History.Process, as: HistoryProcess
alias Explorer.Repo
alias Explorer.Chain.Block
alias Explorer.Chain.Transaction.History.TransactionStats
alias Explorer.Chain.Events.Publisher
import Ecto.Query, only: [from: 2]
alias Explorer.Chain.Transaction
@behaviour Historian
@impl Historian
def compile_records(num_days, records \\ []) do
if num_days == 0 do
#base case
# base case
{:ok, records}
else
day_to_fetch = Date.add(date_today(), -1*(num_days-1))
day_to_fetch = Date.add(date_today(), -1 * (num_days - 1))
earliest = datetime(day_to_fetch, ~T[00:00:00])
latest = datetime(day_to_fetch, ~T[23:59:59])
query = from(
block in Block,
where: (block.timestamp >= ^earliest and block.timestamp <= ^latest),
join: transaction in Transaction,
on: block.hash == transaction.block_hash)
query =
from(block in Block,
where: block.timestamp >= ^earliest and block.timestamp <= ^latest,
join: transaction in Transaction,
on: block.hash == transaction.block_hash
)
num_transactions = Repo.aggregate query, :count, :hash
records = [%{date: day_to_fetch, number_of_transactions: num_transactions} | records ]
compile_records(num_days-1, records)
num_transactions = Repo.aggregate(query, :count, :hash)
records = [%{date: day_to_fetch, number_of_transactions: num_transactions} | records]
compile_records(num_days - 1, records)
end
end
@impl Historian
def save_records(records) do
{num_inserted, _} = Repo.insert_all(TransactionStats, records, on_conflict: :replace_all_except_primary_key, conflict_target: [:date])
{num_inserted, _} =
Repo.insert_all(TransactionStats, records, on_conflict: :replace_all_except_primary_key, conflict_target: [:date])
Publisher.broadcast(:transaction_stats)
num_inserted
end
@ -49,7 +54,7 @@ defmodule Explorer.Chain.Transaction.History.Historian do
DateTime.from_naive!(naive_dt, "Etc/UTC")
end
defp date_today() do
defp date_today do
HistoryProcess.config_or_default(:utc_today, Date.utc_today(), __MODULE__)
end
end

@ -9,7 +9,6 @@ defmodule Explorer.Chain.Transaction.History.TransactionStats do
alias Explorer.Repo
schema "transaction_stats" do
field(:date, :date)
field(:number_of_transactions, :integer)
@ -28,9 +27,11 @@ defmodule Explorer.Chain.Transaction.History.TransactionStats do
@spec by_date_range(Date.t(), Date.t()) :: [__MODULE__]
def by_date_range(earliest, latest) do
# Create a query
query = from stat in __MODULE__,
where: (stat.date >= ^earliest and stat.date<=^latest),
order_by: [desc: :date]
query =
from(stat in __MODULE__,
where: stat.date >= ^earliest and stat.date <= ^latest,
order_by: [desc: :date]
)
Repo.all(query)
end

@ -7,8 +7,8 @@ defmodule Explorer.History.Historian do
Record of historical values for a specific date.
"""
@type record :: %{
date: Date.t()
}
date: Date.t()
}
@doc """
Compile history for a specified amount of units in the past. Units are defined by historian impl
@ -25,8 +25,8 @@ defmodule Explorer.History.Historian do
alias Explorer.History.Historian
def start_link(_) do
#Expansion:
#HistoryProcess.start_link(Explorer.History.Process, [:ok, __MODULE__], name: __MODULE__)
# Expansion:
# HistoryProcess.start_link(Explorer.History.Process, [:ok, __MODULE__], name: __MODULE__)
GenServer.start_link(Explorer.History.Process, [:ok, __MODULE__], name: __MODULE__)
end

@ -1,5 +1,8 @@
defmodule Explorer.History.Process do
@moduledoc """
Creates the GenServer process used by a Historian to compile_history and to save_records.
Specifically used by Market.History.Historian and Transaction.History.Historian
"""
use GenServer
require Logger
@ -34,6 +37,7 @@ defmodule Explorer.History.Process do
def handle_info({:DOWN, _, :process, _, _}, state) do
{:noreply, state}
end
# Actions
@spec successful_compilation(Historian.record(), module()) :: any()
@ -42,9 +46,9 @@ defmodule Explorer.History.Process do
schedule_next_compilation()
end
defp schedule_next_compilation() do
defp schedule_next_compilation do
delay = config_or_default(:history_fetch_interval, :timer.minutes(60))
Process.send_after(self(), {:compile_historical_records, 1,}, delay)
Process.send_after(self(), {:compile_historical_records, 1}, delay)
end
@spec failed_compilation(non_neg_integer(), module(), non_neg_integer()) :: any()

@ -1,4 +1,7 @@
defmodule Explorer.Market.History.Historian do
@moduledoc """
Implements behaviour Historian for Market History. Compiles market history from a source and then saves it into the database.
"""
use Explorer.History.Historian
alias Explorer.History.Process, as: HistoryProcess
alias Explorer.Market
@ -7,11 +10,12 @@ defmodule Explorer.Market.History.Historian do
@impl Historian
def compile_records(previous_days) do
source = HistoryProcess.config_or_default(
:source,
Explorer.Market.History.Source.CryptoCompare,
Explorer.Market.History.Historian
)
source =
HistoryProcess.config_or_default(
:source,
Explorer.Market.History.Source.CryptoCompare,
Explorer.Market.History.Historian
)
source.fetch_history(previous_days)
end

@ -6,29 +6,25 @@ defmodule Explorer.Chain.Transaction.History.HistorianTest do
import Ecto.Query, only: [from: 2]
setup do
Application.put_env(:explorer, Historian, utc_today: ~D[1970-01-04])
:ok
end
defp days_to_secs(days) do
60*60*24*days
60 * 60 * 24 * days
end
describe "compile_records/1" do
test "fetches transactions from blocks mined in the past num_days" do
blocks = [
#1970-01-03 00:00:60
# 1970-01-03 00:00:60
insert(:block, timestamp: DateTime.from_unix!(days_to_secs(2) + 60)),
#1970-01-03 04:00:00
insert(:block, timestamp: DateTime.from_unix!(days_to_secs(2) + (4*60*60))),
# 1970-01-03 04:00:00
insert(:block, timestamp: DateTime.from_unix!(days_to_secs(2) + 4 * 60 * 60)),
#1970-01-02 00:00:00
# 1970-01-02 00:00:00
insert(:block, timestamp: DateTime.from_unix!(days_to_secs(1)))
]
@ -39,22 +35,23 @@ defmodule Explorer.Chain.Transaction.History.HistorianTest do
expected = [
%{date: ~D[1970-01-04], number_of_transactions: 0}
]
assert {:ok, ^expected} = Historian.compile_records 1
assert {:ok, ^expected} = Historian.compile_records(1)
expected = [
%{date: ~D[1970-01-04], number_of_transactions: 0},
%{date: ~D[1970-01-03], number_of_transactions: 2},
%{date: ~D[1970-01-03], number_of_transactions: 2}
]
assert {:ok, ^expected} = Historian.compile_records 2
assert {:ok, ^expected} = Historian.compile_records(2)
expected = [
%{date: ~D[1970-01-04], number_of_transactions: 0},
%{date: ~D[1970-01-03], number_of_transactions: 2},
%{date: ~D[1970-01-02], number_of_transactions: 1}
]
assert {:ok, ^expected} = Historian.compile_records 3
assert {:ok, ^expected} = Historian.compile_records(3)
end
end
@ -73,10 +70,11 @@ defmodule Explorer.Chain.Transaction.History.HistorianTest do
Historian.save_records(single_record)
query = from(
stats in TransactionStats,
select: %{date: stats.date, number_of_transactions: stats.number_of_transactions},
order_by: [desc: stats.date])
query =
from(stats in TransactionStats,
select: %{date: stats.date, number_of_transactions: stats.number_of_transactions},
order_by: [desc: stats.date]
)
results = Repo.all(query)

@ -5,10 +5,11 @@ defmodule Explorer.Chain.Transaction.History.TransactionStatsTest do
alias Explorer.Repo
test "by_date_range()" do
some_transaction_stats = [%{date: ~D[2019-07-09], number_of_transactions: 10},
%{date: ~D[2019-07-08], number_of_transactions: 20},
%{date: ~D[2019-07-07], number_of_transactions: 30}]
some_transaction_stats = [
%{date: ~D[2019-07-09], number_of_transactions: 10},
%{date: ~D[2019-07-08], number_of_transactions: 20},
%{date: ~D[2019-07-07], number_of_transactions: 30}
]
Repo.insert_all(TransactionStats, some_transaction_stats)
@ -22,7 +23,6 @@ defmodule Explorer.Chain.Transaction.History.TransactionStatsTest do
assert ~D[2019-07-07] = Enum.at(all3, 2).date
assert 30 == Enum.at(all3, 2).number_of_transactions
just2 = TransactionStats.by_date_range(~D[2019-07-08], ~D[2019-07-09])
assert 2 == length(just2)
assert ~D[2019-07-08] = Enum.at(just2, 1).date

@ -13,6 +13,7 @@ defmodule Explorer.History.ProcessTest do
test "handle_info with `{:compile_historical_records, days}`" do
records = [%{date: ~D[2018-04-01], closing_price: Decimal.new(10), opening_price: Decimal.new(5)}]
TestHistorian
|> expect(:compile_records, fn 1 -> {:ok, records} end)
|> expect(:save_records, fn _ -> :ok end)
@ -43,7 +44,7 @@ defmodule Explorer.History.ProcessTest do
assert {:noreply, state} == HistoryProcess.handle_info({nil, {1, 0, {:ok, [record]}}}, state)
# Message isn't sent before interval is up
refute_receive {:compile_historical_records, 1}, history_fetch_interval-1
refute_receive {:compile_historical_records, 1}, history_fetch_interval - 1
# Now message is sent
assert_receive {:compile_historical_records, 1}
@ -54,10 +55,9 @@ defmodule Explorer.History.ProcessTest do
|> expect(:compile_records, fn 1 -> :error end)
|> expect(:save_records, fn _ -> :ok end)
#Process will restart, so this is needed
# Process will restart, so this is needed
set_mox_global()
state = %{historian: TestHistorian}
# base_backoff should be short enough that it doesn't slow down testing...
@ -69,7 +69,7 @@ defmodule Explorer.History.ProcessTest do
assert {:noreply, state} == HistoryProcess.handle_info({nil, {1, 0, :error}}, state)
# Message isn't sent before interval is up
refute_receive {_ref, {1, 1, :error}}, base_backoff-1
refute_receive {_ref, {1, 1, :error}}, base_backoff - 1
# Now message is sent
assert_receive {_ref, {1, 1, :error}}

Loading…
Cancel
Save