pull/222/head
Luke Imhoff 7 years ago
parent e05e8b9c25
commit b7aadf26e2
  1. 2
      .formatter.exs
  2. 7
      apps/explorer/README.md
  3. BIN
      apps/explorer/benchmarks/explorer/chain/recent_collated_transactions.benchee
  4. 60
      apps/explorer/benchmarks/explorer/chain/recent_collated_transactions.exs
  5. 4
      apps/explorer/mix.exs
  6. 48
      apps/explorer/test/support/factory.ex
  7. 1
      apps/explorer_web/test/explorer_web/controllers/address_transaction_controller_test.exs
  8. 1
      apps/explorer_web/test/support/conn_case.ex
  9. 36
      apps/explorer_web/test/support/factory.ex
  10. 1
      apps/explorer_web/test/support/feature_case.ex
  11. 2
      coveralls.json
  12. 5
      mix.lock

@ -3,7 +3,7 @@
".credo.exs", ".credo.exs",
".formatter.exs", ".formatter.exs",
"apps/*/mix.exs", "apps/*/mix.exs",
"apps/*/{config,lib,priv,test}/**/*.{ex,exs}", "apps/*/{benchmarks,config,lib,priv,test}/**/*.{ex,exs}",
"mix.exs", "mix.exs",
"{config}/**/*.{ex,exs}" "{config}/**/*.{ex,exs}"
], ],

@ -33,3 +33,10 @@ To get POA Explorer up and running locally:
* Lint the Elixir code: `$ mix credo --strict` * Lint the Elixir code: `$ mix credo --strict`
* Run the dialyzer: `mix dialyzer --halt-exit-status` * Run the dialyzer: `mix dialyzer --halt-exit-status`
* Check the Elixir code for vulnerabilities: `$ mix sobelow --config` * Check the Elixir code for vulnerabilities: `$ mix sobelow --config`
### Benchmarking
#### `Explorer.Chain.recent_collated_transactions/0`
* Reset the test database: `MIX_ENV=test mix do ecto.drop, ecto.create, ecto.migrate`
* Run the benchmark: `MIX_ENV=test mix run benchmarks/explorer/chain/recent_collated_transactions.exs`

@ -0,0 +1,60 @@
path = "benchmarks/explorer/chain/recent_collated_transactions.benchee"
import Explorer.Factory
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block
Benchee.run(
%{
"Explorer.Chain.recent_collated_transactions" => fn _ ->
Chain.recent_collated_transactions()
end
},
inputs: %{
" 0 blocks 0 transactions per block" => %{block_count: 0, transaction_count_per_block: 0},
" 10 blocks 0 transactions per block" => %{block_count: 10, transaction_count_per_block: 0},
" 10 blocks 1 transaction per block" => %{block_count: 10, transaction_count_per_block: 1},
" 10 blocks 10 transactions per blocks" => %{block_count: 10, transaction_count_per_block: 10},
" 10 blocks 100 transactions per blocks" => %{block_count: 10, transaction_count_per_block: 100},
" 10 blocks 250 transactions per blocks" => %{block_count: 10, transaction_count_per_block: 250},
" 100 blocks 0 transactions per block" => %{block_count: 100, transaction_count_per_block: 0},
" 100 blocks 1 transaction per block" => %{block_count: 100, transaction_count_per_block: 1},
" 100 blocks 10 transactions per blocks" => %{block_count: 100, transaction_count_per_block: 10},
" 100 blocks 100 transactions per blocks" => %{block_count: 100, transaction_count_per_block: 100},
" 100 blocks 250 transactions per blocks" => %{block_count: 100, transaction_count_per_block: 250},
"1000 blocks 0 transactions per block" => %{block_count: 1000, transaction_count_per_block: 0},
"1000 blocks 1 transaction per block" => %{block_count: 1000, transaction_count_per_block: 1},
"1000 blocks 10 transactions per blocks" => %{block_count: 1000, transaction_count_per_block: 10},
"1000 blocks 100 transactions per blocks" => %{block_count: 1000, transaction_count_per_block: 100}
},
before_scenario: fn %{block_count: block_count, transaction_count_per_block: transaction_count_per_block} = input ->
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo, ownership_timeout: :infinity)
# ensure database is clean from failed runs
0 = Repo.aggregate(Block, :count, :hash)
block_count
|> insert_list(:block)
|> Enum.each(fn block ->
transaction_count_per_block
|> insert_list(:transaction)
|> Enum.each(fn transaction ->
transaction
|> with_block(block)
|> with_receipt()
end)
end)
input
end,
formatter_options: %{
console: %{extended_statistics: true}
},
load: path,
save: [
path: path,
tag: "separate-receipts"
],
time: 10
)

@ -62,6 +62,10 @@ defmodule Explorer.Mixfile do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
# benchmark optimizations
{:benchee, "~> 0.13.1", only: :test},
# CSV output for benchee
{:benchee_csv, "~> 0.8.0", only: :test},
{:bypass, "~> 0.8", only: :test}, {:bypass, "~> 0.8", only: :test},
{:credo, "0.9.2", only: [:dev, :test], runtime: false}, {:credo, "0.9.2", only: [:dev, :test], runtime: false},
{:crontab, "~> 1.1"}, {:crontab, "~> 1.1"},

@ -1,6 +1,11 @@
defmodule Explorer.Factory do defmodule Explorer.Factory do
use ExMachina.Ecto, repo: Explorer.Repo use ExMachina.Ecto, repo: Explorer.Repo
require Ecto.Query
import Ecto.Query
import Kernel, except: [+: 2]
alias Explorer.Chain.Block.{Range, Reward} alias Explorer.Chain.Block.{Range, Reward}
alias Explorer.Chain.{ alias Explorer.Chain.{
@ -126,8 +131,8 @@ defmodule Explorer.Factory do
def block_reward_factory do def block_reward_factory do
# Generate ranges like 1 - 10,000; 10,001 - 20,000, 20,001 - 30,000; etc # Generate ranges like 1 - 10,000; 10,001 - 20,000, 20,001 - 30,000; etc
x = sequence("block_range", & &1) x = sequence("block_range", & &1)
lower = x * 10_000 + 1 lower = x * Kernel.+(10_000, 1)
upper = lower + 9_999 upper = Kernel.+(lower, 9_999)
wei_per_ether = Decimal.new(1_000_000_000_000_000_000) wei_per_ether = Decimal.new(1_000_000_000_000_000_000)
@ -205,6 +210,45 @@ defmodule Explorer.Factory do
Repo.preload(block_transaction, [:block, :receipt]) Repo.preload(block_transaction, [:block, :receipt])
end end
def with_block(%Transaction{index: nil} = transaction, %Block{hash: block_hash}) do
next_transaction_index = block_hash_to_next_transaction_index(block_hash)
transaction
|> Transaction.changeset(%{block_hash: block_hash, index: next_transaction_index})
|> Repo.update!()
|> Repo.preload(:block)
end
def with_receipt(%Transaction{hash: hash, index: index} = transaction) do
insert(:receipt, transaction_hash: hash, transaction_index: index)
Repo.preload(transaction, :receipt)
end
defmacrop left + right do
quote do
fragment("? + ?", unquote(left), unquote(right))
end
end
defmacrop coalesce(left, right) do
quote do
fragment("coalesce(?, ?)", unquote(left), unquote(right))
end
end
defp block_hash_to_next_transaction_index(block_hash) do
import Kernel, except: [+: 2]
Repo.one!(
from(
transaction in Transaction,
select: coalesce(max(transaction.index), -1) + 1,
where: transaction.block_hash == ^block_hash
)
)
end
defp internal_transaction_factory(:call = type) do defp internal_transaction_factory(:call = type) do
gas = Enum.random(21_000..100_000) gas = Enum.random(21_000..100_000)
gas_used = Enum.random(0..gas) gas_used = Enum.random(0..gas)

@ -2,7 +2,6 @@ defmodule ExplorerWeb.AddressTransactionControllerTest do
use ExplorerWeb.ConnCase use ExplorerWeb.ConnCase
import ExplorerWeb.Router.Helpers, only: [address_transaction_path: 4] import ExplorerWeb.Router.Helpers, only: [address_transaction_path: 4]
import ExplorerWeb.Factory
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token

@ -25,7 +25,6 @@ defmodule ExplorerWeb.ConnCase do
@endpoint ExplorerWeb.Endpoint @endpoint ExplorerWeb.Endpoint
import Explorer.Factory import Explorer.Factory
import ExplorerWeb.Factory
end end
end end

@ -1,36 +0,0 @@
defmodule ExplorerWeb.Factory do
import Ecto.Query
import Explorer.Factory
alias Explorer.Chain.{Block, Transaction}
alias Explorer.Repo
def with_block(%Transaction{index: nil} = transaction, %Block{hash: block_hash}) do
next_transaction_index = block_hash_to_next_transaction_index(block_hash)
transaction
|> Transaction.changeset(%{block_hash: block_hash, index: next_transaction_index})
|> Repo.update!()
|> Repo.preload(:block)
end
def with_receipt(%Transaction{hash: hash, index: index} = transaction) do
insert(:receipt, transaction_hash: hash, transaction_index: index)
Repo.preload(transaction, :receipt)
end
defp block_hash_to_next_transaction_index(block_hash) do
query =
from(
transaction in Transaction,
select: transaction.index,
where: transaction.block_hash == ^block_hash
)
case Repo.one(query) do
nil -> 0
index -> index + 1
end
end
end

@ -12,7 +12,6 @@ defmodule ExplorerWeb.FeatureCase do
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
import Explorer.Factory import Explorer.Factory
import ExplorerWeb.Factory
import ExplorerWeb.Router.Helpers import ExplorerWeb.Router.Helpers
alias Explorer.Repo alias Explorer.Repo

@ -1,7 +1,7 @@
{ {
"coverage_options": { "coverage_options": {
"treat_no_relevant_lines_as_covered": true, "treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 91.9 "minimum_coverage": 92.3
}, },
"terminal_options": { "terminal_options": {
"file_column_width": 120 "file_column_width": 120

@ -1,5 +1,7 @@
%{ %{
"abnf2": {:hex, :abnf2, "0.1.2", "6f8792b8ac3288dba5fc889c2bceae9fe78f74e1a7b36bea9726ffaa9d7bef95", [:mix], [], "hexpm"}, "abnf2": {:hex, :abnf2, "0.1.2", "6f8792b8ac3288dba5fc889c2bceae9fe78f74e1a7b36bea9726ffaa9d7bef95", [:mix], [], "hexpm"},
"benchee": {:hex, :benchee, "0.13.1", "bd93ca05be78bcb6159c7176230efeda2f724f7ffd485515175ca411dff4893e", [:mix], [{:deep_merge, "~> 0.1", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm"},
"benchee_csv": {:hex, :benchee_csv, "0.8.0", "0ca094677d6e2b2f601b7ee7864b754789ef9d24d079432e5e3d6f4fb83a4d80", [:mix], [{:benchee, "~> 0.12", [hex: :benchee, repo: "hexpm", optional: false]}, {:csv, "~> 2.0", [hex: :csv, repo: "hexpm", optional: false]}], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"bypass": {:hex, :bypass, "0.8.1", "16d409e05530ece4a72fabcf021a3e5c7e15dcc77f911423196a0c551f2a15ca", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "bypass": {:hex, :bypass, "0.8.1", "16d409e05530ece4a72fabcf021a3e5c7e15dcc77f911423196a0c551f2a15ca", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:hex, :certifi, "2.3.1", "d0f424232390bf47d82da8478022301c561cf6445b5b5fb6a84d49a9e76d2639", [:rebar3], [{:parse_trans, "3.2.0", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "certifi": {:hex, :certifi, "2.3.1", "d0f424232390bf47d82da8478022301c561cf6445b5b5fb6a84d49a9e76d2639", [:rebar3], [{:parse_trans, "3.2.0", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
@ -9,8 +11,10 @@
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"}, "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"},
"credo": {:hex, :credo, "0.9.2", "841d316612f568beb22ba310d816353dddf31c2d94aa488ae5a27bb53760d0bf", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "credo": {:hex, :credo, "0.9.2", "841d316612f568beb22ba310d816353dddf31c2d94aa488ae5a27bb53760d0bf", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"crontab": {:hex, :crontab, "1.1.2", "4784a50987b4a19af07a908f98e8a308b00f9c93efc5a7892155dc10cd8fc7d9", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crontab": {:hex, :crontab, "1.1.2", "4784a50987b4a19af07a908f98e8a308b00f9c93efc5a7892155dc10cd8fc7d9", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"csv": {:hex, :csv, "2.1.1", "a4c1a7c30d2151b6e4976cb2f52c0a1d49ec965afb737ed84a684bc4284d1627", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"}, "decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"deep_merge": {:hex, :deep_merge, "0.1.1", "c27866a7524a337b6a039eeb8dd4f17d458fd40fbbcb8c54661b71a22fffe846", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"}, "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.8", "a4463c0928b970f2cee722cd29aaac154e866a15882c5737e0038bbfcf03ec2c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "2.2.8", "a4463c0928b970f2cee722cd29aaac154e866a15882c5737e0038bbfcf03ec2c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
@ -43,6 +47,7 @@
"mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mox": {:hex, :mox, "0.3.2", "3b9b8364fd4f28628139de701d97c636b27a8f925f57a8d5a1b85fbd620dad3a", [:mix], [], "hexpm"}, "mox": {:hex, :mox, "0.3.2", "3b9b8364fd4f28628139de701d97c636b27a8f925f57a8d5a1b85fbd620dad3a", [:mix], [], "hexpm"},
"parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},

Loading…
Cancel
Save