FORMAT ALL TEH THINGS

pull/42/head
CJ Bryan and Desmond Bowe 7 years ago
parent 99615e86c6
commit 5f937d84ed
  1. 5
      .formatter.exs
  2. 1
      circle.yml
  3. 19
      config/config.exs
  4. 30
      config/dev.exs
  5. 37
      config/prod.exs
  6. 6
      config/test.exs
  7. 18
      lib/explorer/address.ex
  8. 10
      lib/explorer/application.ex
  9. 34
      lib/explorer/block.ex
  10. 13
      lib/explorer/block_transaction.ex
  11. 22
      lib/explorer/chain.ex
  12. 13
      lib/explorer/credit.ex
  13. 13
      lib/explorer/debit.ex
  14. 4
      lib/explorer/forms/address_form.ex
  15. 13
      lib/explorer/forms/block_form.ex
  16. 8
      lib/explorer/forms/pending_transaction_form.ex
  17. 34
      lib/explorer/forms/transaction_form.ex
  18. 13
      lib/explorer/from_address.ex
  19. 19
      lib/explorer/importers/block_importer.ex
  20. 15
      lib/explorer/importers/internal_transaction_importer.ex
  21. 14
      lib/explorer/importers/receipt_importer.ex
  22. 32
      lib/explorer/importers/transaction_importer.ex
  23. 28
      lib/explorer/internal_transaction.ex
  24. 26
      lib/explorer/log.ex
  25. 18
      lib/explorer/receipt.ex
  26. 16
      lib/explorer/resource.ex
  27. 5
      lib/explorer/servers/chain_statistics.ex
  28. 9
      lib/explorer/services/transaction.ex
  29. 9
      lib/explorer/skipped_blocks.ex
  30. 7
      lib/explorer/skipped_receipts.ex
  31. 13
      lib/explorer/to_address.ex
  32. 46
      lib/explorer/transaction.ex
  33. 4
      lib/explorer/workers/import_skipped_blocks.ex
  34. 13
      lib/explorer/workers/refresh_balance.ex
  35. 3
      lib/explorer_web.ex
  36. 2
      lib/explorer_web/channels/user_socket.ex
  37. 6
      lib/explorer_web/controllers/address_controller.ex
  38. 18
      lib/explorer_web/controllers/address_transaction_from_controller.ex
  39. 18
      lib/explorer_web/controllers/address_transaction_to_controller.ex
  40. 14
      lib/explorer_web/controllers/block_controller.ex
  41. 6
      lib/explorer_web/controllers/block_transaction_controller.ex
  42. 16
      lib/explorer_web/controllers/chain_controller.ex
  43. 6
      lib/explorer_web/controllers/internal_transaction_controller.ex
  44. 29
      lib/explorer_web/controllers/pending_transaction_controller.ex
  45. 50
      lib/explorer_web/controllers/transaction_controller.ex
  46. 7
      lib/explorer_web/controllers/transaction_log_controller.ex
  47. 36
      lib/explorer_web/endpoint.ex
  48. 9
      lib/explorer_web/gettext.ex
  49. 86
      lib/explorer_web/router.ex
  50. 4
      lib/explorer_web/views/error_helpers.ex
  51. 2
      lib/explorer_web/views/error_view.ex
  52. 2
      lib/explorer_web/views/transaction_view.ex
  53. 2
      lib/mix/tasks/exq.start.ex
  54. 2
      lib/mix/tasks/scrape.blocks.ex
  55. 2
      lib/mix/tasks/scrape.receipts.ex
  56. 36
      mix.exs
  57. 4
      test/explorer/address_test.exs
  58. 16
      test/explorer/block_test.exs
  59. 5
      test/explorer/chain_test.exs
  60. 16
      test/explorer/credit_test.exs
  61. 16
      test/explorer/debit_test.exs
  62. 7
      test/explorer/forms/address_form_test.exs
  63. 2
      test/explorer/forms/block_form_test.exs
  64. 12
      test/explorer/forms/pending_transaction_form_test.exs
  65. 161
      test/explorer/forms/transaction_form_test.exs
  66. 51
      test/explorer/importers/block_importer_test.exs
  67. 43
      test/explorer/importers/internal_transaction_importer_test.exs
  68. 94
      test/explorer/importers/receipt_importer_test.exs
  69. 185
      test/explorer/importers/transaction_importer_test.exs
  70. 32
      test/explorer/internal_transaction_test.exs
  71. 2
      test/explorer/receipt_test.exs
  72. 17
      test/explorer/transaction_test.exs
  73. 16
      test/explorer/workers/import_block_test.exs
  74. 18
      test/explorer/workers/import_receipt_test.exs
  75. 5
      test/explorer/workers/import_skipped_blocks_test.exs
  76. 71
      test/explorer/workers/import_transaction_test.exs
  77. 8
      test/explorer/workers/refresh_balance_test.exs
  78. 4
      test/explorer_web/controllers/address_controller_test.exs
  79. 25
      test/explorer_web/controllers/address_transaction_from_controller_test.exs
  80. 25
      test/explorer_web/controllers/address_transaction_to_controller_test.exs
  81. 8
      test/explorer_web/controllers/block_controller_test.exs
  82. 39
      test/explorer_web/controllers/chain_controller_test.exs
  83. 9
      test/explorer_web/controllers/pending_transaction_controller_test.exs
  84. 4
      test/explorer_web/controllers/transaction_controller_test.exs
  85. 72
      test/explorer_web/features/contributor_browsing_test.exs
  86. 9
      test/explorer_web/views/error_view_test.exs
  87. 4
      test/support/channel_case.ex
  88. 2
      test/support/conn_case.ex
  89. 2
      test/support/factories/block_factory.ex
  90. 2
      test/support/factories/internal_transaction_factory.ex
  91. 2
      test/support/factories/log_factory.ex
  92. 2
      test/support/factories/receipt_factory.ex
  93. 16
      test/support/factories/transaction_factory.ex
  94. 4
      test/test_helper.exs

@ -0,0 +1,5 @@
[
inputs: [
"mix.exs", "{config,lib,test}/**/*.{ex,exs}"
]
]

@ -55,6 +55,7 @@ dependencies:
test:
pre:
- mix format --check-formatted
- mix credo
- mix sobelow --config
- mix dialyzer --halt-exit-status

@ -6,8 +6,7 @@
use Mix.Config
# General application configuration
config :explorer,
ecto_repos: [Explorer.Repo]
config :explorer, ecto_repos: [Explorer.Repo]
# Configures gettext
config :explorer, ExplorerWeb.Gettext, locales: ~w(en), default_locale: "en"
@ -18,21 +17,18 @@ config :explorer, ExplorerWeb.Endpoint,
render_errors: [view: ExplorerWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: Explorer.PubSub, adapter: Phoenix.PubSub.PG2]
config :explorer, Explorer.Integrations.EctoLogger,
query_time_ms_threshold: 2_000
config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: 2_000
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
config :ethereumex,
url: "http://localhost:8545"
config :ethereumex, url: "http://localhost:8545"
config :new_relixir,
active: false
config :new_relixir, active: false
config :ex_cldr,
config :ex_cldr,
default_locale: "en",
locales: ["en"],
gettext: ExplorerWeb.Gettext
@ -47,9 +43,8 @@ config :exq,
max_retries: 10,
queues: [{"default", 1}, {"blocks", 1}, {"transactions", 1}, {"receipts", 1}]
config :exq_ui,
server: false
config :exq_ui, server: false
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs"
import_config "#{Mix.env()}.exs"

@ -11,8 +11,14 @@ config :explorer, ExplorerWeb.Endpoint,
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [node: ["node_modules/brunch/bin/brunch", "watch", "--stdin",
cd: Path.expand("../assets", __DIR__)]]
watchers: [
node: [
"node_modules/brunch/bin/brunch",
"watch",
"--stdin",
cd: Path.expand("../assets", __DIR__)
]
]
# ## SSL Support
#
@ -58,10 +64,22 @@ config :explorer, Explorer.Repo,
# Configure Quantum
config :explorer, Explorer.Scheduler,
jobs: [
[schedule: {:extended, "*/15 * * * * *"}, task: {Explorer.Workers.RefreshBalance, :perform_later, []}],
[schedule: {:extended, "*/5 * * * * *"}, task: {Explorer.Workers.ImportBlock, :perform_later, ["latest"]}],
[schedule: {:extended, "*/5 * * * * *"}, task: {Explorer.Workers.ImportBlock, :perform_later, ["pending"]}],
[schedule: {:extended, "*/15 * * * * *"}, task: {Explorer.Workers.ImportSkippedBlocks, :perform_later, [1]}],
[
schedule: {:extended, "*/15 * * * * *"},
task: {Explorer.Workers.RefreshBalance, :perform_later, []}
],
[
schedule: {:extended, "*/5 * * * * *"},
task: {Explorer.Workers.ImportBlock, :perform_later, ["latest"]}
],
[
schedule: {:extended, "*/5 * * * * *"},
task: {Explorer.Workers.ImportBlock, :perform_later, ["pending"]}
],
[
schedule: {:extended, "*/15 * * * * *"},
task: {Explorer.Workers.ImportSkippedBlocks, :perform_later, [1]}
]
]
import_config "dev.secret.exs"

@ -18,9 +18,17 @@ config :explorer, ExplorerWeb.Endpoint,
force_ssl: [rewrite_on: [:x_forwarded_proto]],
instrumenters: [NewRelixir.Instrumenters.Phoenix],
load_from_system_env: true,
pubsub: [adapter: Phoenix.PubSub.Redis, url: System.get_env("REDIS_URL"), node_name: System.get_env("DYNO")],
pubsub: [
adapter: Phoenix.PubSub.Redis,
url: System.get_env("REDIS_URL"),
node_name: System.get_env("DYNO")
],
secret_key_base: System.get_env("SECRET_KEY_BASE"),
url: [scheme: "https", host: Map.fetch!(System.get_env(), "HEROKU_APP_NAME") <> ".herokuapp.com", port: 443]
url: [
scheme: "https",
host: Map.fetch!(System.get_env(), "HEROKU_APP_NAME") <> ".herokuapp.com",
port: 443
]
# Do not print debug messages in production
config :logger, level: :info
@ -42,16 +50,29 @@ config :new_relixir,
active: true
# Configure Web3
config :ethereumex,
url: System.get_env("ETHEREUM_URL")
config :ethereumex, url: System.get_env("ETHEREUM_URL")
# Configure Quantum
config :explorer, Explorer.Scheduler,
jobs: [
[schedule: {:extended, System.get_env("EXQ_BALANCE_SCHEDULE") || "0 * * * * *"}, task: {Explorer.Workers.RefreshBalance, :perform_later, []}],
[schedule: {:extended, System.get_env("EXQ_LATEST_BLOCK_SCHEDULE") || "* * * * * *"}, task: {Explorer.Workers.ImportBlock, :perform_later, ["latest"]}],
[schedule: {:extended, System.get_env("EXQ_PENDING_BLOCK_SCHEDULE") || "* * * * * *"}, task: {Explorer.Workers.ImportBlock, :perform_later, ["pending"]}],
[schedule: {:extended, System.get_env("EXQ_BACKFILL_SCHEDULE") || "* * * * * *"}, task: {Explorer.Workers.ImportSkippedBlocks, :perform_later, [String.to_integer(System.get_env("EXQ_BACKFILL_BATCH_SIZE") || "1")]}],
[
schedule: {:extended, System.get_env("EXQ_BALANCE_SCHEDULE") || "0 * * * * *"},
task: {Explorer.Workers.RefreshBalance, :perform_later, []}
],
[
schedule: {:extended, System.get_env("EXQ_LATEST_BLOCK_SCHEDULE") || "* * * * * *"},
task: {Explorer.Workers.ImportBlock, :perform_later, ["latest"]}
],
[
schedule: {:extended, System.get_env("EXQ_PENDING_BLOCK_SCHEDULE") || "* * * * * *"},
task: {Explorer.Workers.ImportBlock, :perform_later, ["pending"]}
],
[
schedule: {:extended, System.get_env("EXQ_BACKFILL_SCHEDULE") || "* * * * * *"},
task:
{Explorer.Workers.ImportSkippedBlocks, :perform_later,
[String.to_integer(System.get_env("EXQ_BACKFILL_BATCH_SIZE") || "1")]}
]
]
# Configure Exq

@ -21,9 +21,7 @@ config :explorer, Explorer.Repo,
ownership_timeout: 60_000
# Configure wallaby
config :wallaby,
screenshot_on_failure: true
config :wallaby, screenshot_on_failure: true
# Configure ethereumex
config :ethereumex,
url: "https://sokol-trace.poa.network"
config :ethereumex, url: "https://sokol-trace.poa.network"

@ -13,13 +13,15 @@ defmodule Explorer.Address do
alias Explorer.Debit
alias Explorer.Repo.NewRelic, as: Repo
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
schema "addresses" do
has_one :credit, Credit
has_one :debit, Debit
field :hash, :string
has_one(:credit, Credit)
has_one(:debit, Debit)
field(:hash, :string)
timestamps()
end
@ -27,9 +29,13 @@ defmodule Explorer.Address do
@optional_attrs ~w()a
def find_or_create_by_hash(hash) do
query = from a in Address,
query =
from(
a in Address,
where: fragment("lower(?)", a.hash) == ^String.downcase(hash),
limit: 1
)
case query |> Repo.one() do
nil -> Repo.insert!(Address.changeset(%Address{}, %{hash: hash}))
address -> address

@ -11,7 +11,7 @@ defmodule Explorer.Application do
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Explorer.Supervisor]
Supervisor.start_link(children(Mix.env), opts)
Supervisor.start_link(children(Mix.env()), opts)
end
# Tell Phoenix to update the endpoint configuration
@ -23,10 +23,13 @@ defmodule Explorer.Application do
end
defp children(:test), do: children()
defp children(_) do
import Supervisor.Spec
exq_options = [] |> Keyword.put(:mode, :enqueuer)
children() ++ [
children() ++
[
supervisor(Exq, [exq_options]),
worker(Explorer.Servers.ChainStatistics, [])
]
@ -34,9 +37,10 @@ defmodule Explorer.Application do
defp children do
import Supervisor.Spec
[
supervisor(Explorer.Repo, []),
supervisor(ExplorerWeb.Endpoint, []),
supervisor(ExplorerWeb.Endpoint, [])
]
end
end

@ -12,24 +12,26 @@ defmodule Explorer.Block do
alias Explorer.BlockTransaction
alias Explorer.Transaction
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
schema "blocks" do
has_many :block_transactions, BlockTransaction
many_to_many :transactions, Transaction, join_through: "block_transactions"
field :number, :integer
field :hash, :string
field :parent_hash, :string
field :nonce, :string
field :miner, :string
field :difficulty, :decimal
field :total_difficulty, :decimal
field :size, :integer
field :gas_limit, :integer
field :gas_used, :integer
field :timestamp, Timex.Ecto.DateTime
has_many(:block_transactions, BlockTransaction)
many_to_many(:transactions, Transaction, join_through: "block_transactions")
field(:number, :integer)
field(:hash, :string)
field(:parent_hash, :string)
field(:nonce, :string)
field(:miner, :string)
field(:difficulty, :decimal)
field(:total_difficulty, :decimal)
field(:size, :integer)
field(:gas_limit, :integer)
field(:gas_used, :integer)
field(:timestamp, Timex.Ecto.DateTime)
timestamps()
end

@ -4,13 +4,15 @@ defmodule Explorer.BlockTransaction do
import Ecto.Changeset
use Ecto.Schema
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@primary_key false
schema "block_transactions" do
belongs_to :block, Explorer.Block
belongs_to :transaction, Explorer.Transaction, primary_key: true
belongs_to(:block, Explorer.Block)
belongs_to(:transaction, Explorer.Transaction, primary_key: true)
timestamps()
end
@ -22,7 +24,6 @@ defmodule Explorer.BlockTransaction do
|> validate_required(@required_attrs)
|> cast_assoc(:block)
|> cast_assoc(:transaction)
|> unique_constraint(:transaction_id,
name: :block_transactions_transaction_id_index)
|> unique_constraint(:transaction_id, name: :block_transactions_transaction_id_index)
end
end

@ -11,8 +11,7 @@ defmodule Explorer.Chain do
alias Explorer.Repo, as: Repo
alias Timex.Duration
defstruct [
number: -1,
defstruct number: -1,
timestamp: :calendar.universal_time(),
average_time: %Duration{seconds: 0, megaseconds: 0, microseconds: 0},
lag: %Duration{seconds: 0, megaseconds: 0, microseconds: 0},
@ -22,7 +21,6 @@ defmodule Explorer.Chain do
transaction_velocity: 0,
blocks: [],
transactions: []
]
@average_time_query """
SELECT coalesce(avg(difference), interval '0 seconds')
@ -71,19 +69,26 @@ defmodule Explorer.Chain do
"""
def fetch do
blocks = from block in Block,
blocks =
from(
block in Block,
order_by: [desc: block.number],
preload: :transactions,
limit: 5
)
transactions = from transaction in Transaction,
transactions =
from(
transaction in Transaction,
join: block in assoc(transaction, :block),
order_by: [desc: block.number],
preload: [block: block],
limit: 5
)
last_block = Block |> Block.latest() |> limit(1) |> Repo.one()
latest_block = last_block || Block.null
latest_block = last_block || Block.null()
%Explorer.Chain{
number: latest_block.number,
timestamp: latest_block.timestamp,
@ -105,10 +110,13 @@ defmodule Explorer.Chain do
defp query_duration(query) do
results = SQL.query!(Repo, query, [])
{:ok, value} = results.rows
{:ok, value} =
results.rows
|> List.first()
|> List.first()
|> Timex.Ecto.Time.load()
value
end
end

@ -9,19 +9,22 @@ defmodule Explorer.Credit do
alias Explorer.Address
alias Explorer.Repo
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@primary_key false
schema "credits" do
belongs_to :address, Address, primary_key: true
field :value, :decimal
field :count, :integer
belongs_to(:address, Address, primary_key: true)
field(:value, :decimal)
field(:count, :integer)
timestamps()
end
def refresh do
SQL.query!(Repo, "REFRESH MATERIALIZED VIEW CONCURRENTLY credits;", [], timeout: 120_000)
end
def null, do: %__MODULE__{value: Decimal.new(0), count: 0}
end

@ -9,19 +9,22 @@ defmodule Explorer.Debit do
alias Explorer.Address
alias Explorer.Repo
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@primary_key false
schema "debits" do
belongs_to :address, Address, primary_key: true
field :value, :decimal
field :count, :integer
belongs_to(:address, Address, primary_key: true)
field(:value, :decimal)
field(:count, :integer)
timestamps()
end
def refresh do
SQL.query!(Repo, "REFRESH MATERIALIZED VIEW CONCURRENTLY debits;", [], timeout: 120_000)
end
def null, do: %__MODULE__{value: Decimal.new(0), count: 0}
end

@ -5,8 +5,8 @@ defmodule Explorer.AddressForm do
alias Explorer.Debit
def build(address) do
credit = address.credit || Credit.null
debit = address.debit || Debit.null
credit = address.credit || Credit.null()
debit = address.debit || Debit.null()
balance = Decimal.sub(credit.value, debit.value)
Map.put(address, :balance, balance)
end

@ -6,24 +6,29 @@ defmodule Explorer.BlockForm do
import Ecto.Query
def build(block) do
block |> Map.merge(%{
block
|> Map.merge(%{
transactions_count: block |> get_transactions_count,
age: block |> calculate_age,
formatted_timestamp: block |> format_timestamp,
formatted_timestamp: block |> format_timestamp
})
end
def get_transactions_count(block) do
query = from block_transaction in BlockTransaction,
query =
from(
block_transaction in BlockTransaction,
join: block in Block,
where: block.id == block_transaction.block_id,
where: block.id == ^block.id,
select: count(block_transaction.block_id)
)
Repo.one(query)
end
def calculate_age(block) do
block.timestamp |> Timex.from_now
block.timestamp |> Timex.from_now()
end
def format_timestamp(block) do

@ -15,18 +15,18 @@ defmodule Explorer.PendingTransactionForm do
end
def to_address_hash(transaction) do
transaction.to_address && transaction.to_address.hash || nil
(transaction.to_address && transaction.to_address.hash) || nil
end
def from_address_hash(transaction) do
transaction.to_address && transaction.from_address.hash || nil
(transaction.to_address && transaction.from_address.hash) || nil
end
def first_seen(transaction) do
transaction.inserted_at |> Timex.from_now
transaction.inserted_at |> Timex.from_now()
end
def last_seen(transaction) do
transaction.updated_at |> Timex.from_now
transaction.updated_at |> Timex.from_now()
end
end

@ -10,9 +10,9 @@ defmodule Explorer.TransactionForm do
alias Explorer.Repo
def build(transaction) do
block = Ecto.assoc_loaded?(transaction.block) && transaction.block || nil
block = (Ecto.assoc_loaded?(transaction.block) && transaction.block) || nil
receipt = Ecto.assoc_loaded?(transaction.receipt) && transaction.receipt
status = status(transaction, receipt || Receipt.null)
status = status(transaction, receipt || Receipt.null())
%{
block_number: block |> block_number,
@ -26,7 +26,7 @@ defmodule Explorer.TransactionForm do
status: status,
formatted_status: status |> format_status,
first_seen: transaction |> first_seen,
last_seen: transaction |> last_seen,
last_seen: transaction |> last_seen
}
end
@ -35,36 +35,37 @@ defmodule Explorer.TransactionForm do
end
def block_number(block) do
block && block.number || ""
(block && block.number) || ""
end
def block_age(block) do
block && block.timestamp |> Timex.from_now || gettext("Pending")
(block && block.timestamp |> Timex.from_now()) || gettext("Pending")
end
def format_age(block) do
block && "#{block_age(block)} (#{format_timestamp(block)})" || gettext("Pending")
(block && "#{block_age(block)} (#{format_timestamp(block)})") || gettext("Pending")
end
def format_timestamp(block) do
block && block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime) || gettext("Pending")
(block && block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)) ||
gettext("Pending")
end
def cumulative_gas_used(block) do
block && block.gas_used |> Number.to_string! || gettext("Pending")
(block && block.gas_used |> Number.to_string!()) || gettext("Pending")
end
def to_address_hash(transaction) do
transaction.to_address && transaction.to_address.hash || nil
(transaction.to_address && transaction.to_address.hash) || nil
end
def from_address_hash(transaction) do
transaction.to_address && transaction.from_address.hash || nil
(transaction.to_address && transaction.from_address.hash) || nil
end
def confirmations(block) do
query = from block in Block, select: max(block.number)
block && Repo.one(query) - block.number || 0
query = from(block in Block, select: max(block.number))
(block && Repo.one(query) - block.number) || 0
end
def status(transaction, receipt) do
@ -81,15 +82,16 @@ defmodule Explorer.TransactionForm do
out_of_gas: gettext("Out of Gas"),
failed: gettext("Failed"),
success: gettext("Success"),
pending: gettext("Pending"),
} |> Map.fetch!(status)
pending: gettext("Pending")
}
|> Map.fetch!(status)
end
def first_seen(transaction) do
transaction.inserted_at |> Timex.from_now
transaction.inserted_at |> Timex.from_now()
end
def last_seen(transaction) do
transaction.updated_at |> Timex.from_now
transaction.updated_at |> Timex.from_now()
end
end

@ -4,20 +4,21 @@ defmodule Explorer.FromAddress do
import Ecto.Changeset
use Ecto.Schema
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@primary_key false
schema "from_addresses" do
belongs_to :transaction, Explorer.Transaction, primary_key: true
belongs_to :address, Explorer.Address
belongs_to(:transaction, Explorer.Transaction, primary_key: true)
belongs_to(:address, Explorer.Address)
timestamps()
end
def changeset(%FromAddress{} = to_address, attrs \\ %{}) do
to_address
|> cast(attrs, [:transaction_id, :address_id])
|> unique_constraint(:transaction_id,
name: :from_addresses_transaction_id_index)
|> unique_constraint(:transaction_id, name: :from_addresses_transaction_id_index)
end
end

@ -12,7 +12,7 @@ defmodule Explorer.BlockImporter do
changes = extract_block(raw_block)
block = changes.hash |> find()
if is_nil(block.id), do: block |> Block.changeset(changes) |> Repo.insert
if is_nil(block.id), do: block |> Block.changeset(changes) |> Repo.insert()
Enum.map(raw_block["transactions"], &ImportTransaction.perform/1)
end
@ -30,17 +30,23 @@ defmodule Explorer.BlockImporter do
end
def find(hash) do
query = from b in Block,
query =
from(
b in Block,
where: fragment("lower(?)", b.hash) == ^String.downcase(hash),
limit: 1
(query |> Repo.one()) || %Block{}
)
query |> Repo.one() || %Block{}
end
@dialyzer {:nowarn_function, download_block: 1}
def download_block(block_number) do
{:ok, block} = block_number
{:ok, block} =
block_number
|> encode_number()
|> eth_get_block_by_number(true)
block
end
@ -56,7 +62,7 @@ defmodule Explorer.BlockImporter do
total_difficulty: raw_block["totalDifficulty"] |> decode_integer_field,
size: raw_block["size"] |> decode_integer_field,
gas_limit: raw_block["gasLimit"] |> decode_integer_field,
nonce: raw_block["nonce"] || "0",
nonce: raw_block["nonce"] || "0"
}
end
@ -64,6 +70,7 @@ defmodule Explorer.BlockImporter do
defp encode_number("earliest"), do: "earliest"
defp encode_number("pending"), do: "pending"
defp encode_number("0x" <> number) when is_binary(number), do: number
defp encode_number(number) when is_binary(number) do
number
|> String.to_integer()
@ -78,6 +85,6 @@ defmodule Explorer.BlockImporter do
end
def decode_time_field(field) do
field |> decode_integer_field |> Timex.from_unix
field |> decode_integer_field |> Timex.from_unix()
end
end

@ -12,6 +12,7 @@ defmodule Explorer.InternalTransactionImporter do
@dialyzer {:nowarn_function, import: 1}
def import(hash) do
transaction = find_transaction(hash)
hash
|> download_trace
|> extract_attrs
@ -24,9 +25,13 @@ defmodule Explorer.InternalTransactionImporter do
end
defp find_transaction(hash) do
query = from t in Transaction,
query =
from(
t in Transaction,
where: fragment("lower(?)", t.hash) == ^String.downcase(hash),
limit: 1
)
Repo.one!(query)
end
@ -47,12 +52,13 @@ defmodule Explorer.InternalTransactionImporter do
gas: trace["action"]["gas"] |> decode_integer_field,
gas_used: trace["result"]["gasUsed"] |> decode_integer_field,
input: trace["action"]["input"],
output: trace["result"]["output"],
output: trace["result"]["output"]
}
end
defp to_address(%{"action" => %{"to" => address}})
when not is_nil(address), do: address
when not is_nil(address),
do: address
defp to_address(%{"result" => %{"address" => address}}), do: address
@ -60,8 +66,9 @@ defmodule Explorer.InternalTransactionImporter do
@dialyzer {:nowarn_function, persist_internal_transactions: 2}
defp persist_internal_transactions(traces, transaction) do
Enum.map(traces, fn(trace) ->
Enum.map(traces, fn trace ->
trace = Map.merge(trace, %{transaction_id: transaction.id})
%InternalTransaction{}
|> InternalTransaction.changeset(trace)
|> Repo.insert()

@ -11,6 +11,7 @@ defmodule Explorer.ReceiptImporter do
def import(hash) do
transaction = hash |> find_transaction()
hash
|> download_receipt()
|> extract_receipt()
@ -25,12 +26,16 @@ defmodule Explorer.ReceiptImporter do
end
defp find_transaction(hash) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
left_join: receipt in assoc(transaction, :receipt),
where: fragment("lower(?)", transaction.hash) == ^hash,
where: is_nil(receipt.id),
limit: 1
Repo.one(query) || Transaction.null
)
Repo.one(query) || Transaction.null()
end
defp save_receipt(receipt) do
@ -43,6 +48,7 @@ defmodule Explorer.ReceiptImporter do
defp extract_receipt(receipt) do
logs = receipt["logs"] || []
%{
index: receipt["transactionIndex"] |> decode_integer_field(),
cumulative_gas_used: receipt["cumulativeGasUsed"] |> decode_integer_field(),
@ -54,6 +60,7 @@ defmodule Explorer.ReceiptImporter do
defp extract_log(log) do
address = Address.find_or_create_by_hash(log["address"])
%{
address_id: address.id,
index: log["logIndex"] |> decode_integer_field(),
@ -62,12 +69,13 @@ defmodule Explorer.ReceiptImporter do
first_topic: log["topics"] |> Enum.at(0),
second_topic: log["topics"] |> Enum.at(1),
third_topic: log["topics"] |> Enum.at(2),
fourth_topic: log["topics"] |> Enum.at(3),
fourth_topic: log["topics"] |> Enum.at(3)
}
end
defp decode_integer_field("0x" <> hex) when is_binary(hex) do
String.to_integer(hex, 16)
end
defp decode_integer_field(field), do: field
end

@ -23,14 +23,18 @@ defmodule Explorer.TransactionImporter do
def persist_transaction(raw_transaction) do
found_transaction = raw_transaction["hash"] |> find()
transaction = case is_nil(found_transaction.id) do
false -> found_transaction
transaction =
case is_nil(found_transaction.id) do
false ->
found_transaction
true ->
changes = extract_attrs(raw_transaction)
found_transaction |> Transaction.changeset(changes) |> Repo.insert!
found_transaction |> Transaction.changeset(changes) |> Repo.insert!()
end
to_address = raw_transaction["to"] || raw_transaction["creates"]
transaction
|> create_from_address(raw_transaction["from"])
|> create_to_address(to_address)
@ -38,10 +42,14 @@ defmodule Explorer.TransactionImporter do
end
def find(hash) do
query = from t in Transaction,
query =
from(
t in Transaction,
where: fragment("lower(?)", t.hash) == ^String.downcase(hash),
limit: 1
(query |> Repo.one()) || %Transaction{}
)
query |> Repo.one() || %Transaction{}
end
def download_transaction(hash) do
@ -62,27 +70,33 @@ defmodule Explorer.TransactionImporter do
s: raw_transaction["s"],
standard_v: raw_transaction["standardV"],
transaction_index: raw_transaction["transactionIndex"],
v: raw_transaction["v"],
v: raw_transaction["v"]
}
end
def create_block_transaction(transaction, hash) do
query = from t in Block,
query =
from(
t in Block,
where: fragment("lower(?)", t.hash) == ^String.downcase(hash),
limit: 1
)
block = query |> Repo.one()
if block do
changes = %{block_id: block.id, transaction_id: transaction.id}
case Repo.get_by(BlockTransaction, transaction_id: transaction.id) do
nil ->
%BlockTransaction{}
|> BlockTransaction.changeset(changes)
|> Repo.insert
|> Repo.insert()
block_transaction ->
block_transaction
|> BlockTransaction.changeset(%{block_id: block.id})
|> Repo.update
|> Repo.update()
end
end

@ -9,21 +9,23 @@ defmodule Explorer.InternalTransaction do
alias Explorer.Transaction
alias Explorer.Address
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
schema "internal_transactions" do
belongs_to :transaction, Transaction
belongs_to :from_address, Address
belongs_to :to_address, Address
field :index, :integer
field :call_type, :string
field :trace_address, {:array, :integer}
field :value, :decimal
field :gas, :decimal
field :gas_used, :decimal
field :input, :string
field :output, :string
belongs_to(:transaction, Transaction)
belongs_to(:from_address, Address)
belongs_to(:to_address, Address)
field(:index, :integer)
field(:call_type, :string)
field(:trace_address, {:array, :integer})
field(:value, :decimal)
field(:gas, :decimal)
field(:gas_used, :decimal)
field(:input, :string)
field(:output, :string)
timestamps()
end

@ -9,8 +9,10 @@ defmodule Explorer.Log do
alias Explorer.Log
alias Explorer.Receipt
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@required_attrs ~w(index data type)a
@optional_attrs ~w(
@ -18,16 +20,16 @@ defmodule Explorer.Log do
)a
schema "logs" do
belongs_to :receipt, Receipt
belongs_to :address, Address
has_one :transaction, through: [:receipt, :transaction]
field :index, :integer
field :data, :string
field :type, :string
field :first_topic, :string
field :second_topic, :string
field :third_topic, :string
field :fourth_topic, :string
belongs_to(:receipt, Receipt)
belongs_to(:address, Address)
has_one(:transaction, through: [:receipt, :transaction])
field(:index, :integer)
field(:data, :string)
field(:type, :string)
field(:first_topic, :string)
field(:second_topic, :string)
field(:third_topic, :string)
field(:fourth_topic, :string)
timestamps()
end

@ -9,19 +9,21 @@ defmodule Explorer.Receipt do
alias Explorer.Log
alias Explorer.Receipt
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@required_attrs ~w(cumulative_gas_used gas_used status index)a
@optional_attrs ~w(transaction_id)a
schema "receipts" do
belongs_to :transaction, Transaction
has_many :logs, Log
field :cumulative_gas_used, :decimal
field :gas_used, :decimal
field :status, :integer
field :index, :integer
belongs_to(:transaction, Transaction)
has_many(:logs, Log)
field(:cumulative_gas_used, :decimal)
field(:gas_used, :decimal)
field(:status, :integer)
field(:index, :integer)
timestamps()
end

@ -1,5 +1,4 @@
defmodule Explorer.Resource do
@moduledoc "Looks up and fetches resource based on its handle (either an id or hash)"
import Ecto.Query, only: [from: 2]
@ -16,17 +15,23 @@ defmodule Explorer.Resource do
def lookup(number), do: fetch_block(number)
def fetch_address(hash) do
query = from address in Address,
query =
from(
address in Address,
where: fragment("lower(?)", address.hash) == ^String.downcase(hash),
limit: 1
)
Repo.one(query)
end
def fetch_transaction(hash) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
where: fragment("lower(?)", transaction.hash) == ^String.downcase(hash),
limit: 1
)
Repo.one(query)
end
@ -39,9 +44,12 @@ defmodule Explorer.Resource do
end
def fetch_block(number) when is_integer(number) do
query = from b in Block,
query =
from(
b in Block,
where: b.number == ^number,
limit: 1
)
Repo.one(query)
end

@ -15,6 +15,7 @@ defmodule Explorer.Servers.ChainStatistics do
end
def start_link, do: start_link(true)
def start_link(refresh) do
GenServer.start_link(__MODULE__, refresh, name: __MODULE__)
end
@ -30,14 +31,18 @@ defmodule Explorer.Servers.ChainStatistics do
Task.start_link(fn ->
GenServer.cast(__MODULE__, {:update, Chain.fetch()})
end)
{:noreply, chain}
end
def handle_info(_, %Chain{} = chain), do: {:noreply, chain}
def handle_call(:fetch, _, %Chain{} = chain), do: {:reply, chain, chain}
def handle_call(_, _, %Chain{} = chain), do: {:noreply, chain}
def handle_cast({:update, %Chain{} = chain}, %Chain{} = _) do
Process.send_after(self(), :refresh, @interval)
{:noreply, chain}
end
def handle_cast(_, %Chain{} = chain), do: {:noreply, chain}
end

@ -18,17 +18,20 @@ defmodule Explorer.Transaction.Service do
import Ecto.Query, only: [from: 2]
def for_transaction(query, hash) do
from(child in query,
from(
child in query,
inner_join: transaction in assoc(child, :transaction),
where: fragment("lower(?)", transaction.hash) == ^String.downcase(hash)
)
end
def join_from_and_to_addresses(query) do
from(q in query,
from(
q in query,
inner_join: to_address in assoc(q, :to_address),
inner_join: from_address in assoc(q, :from_address),
preload: [:to_address, :from_address])
preload: [:to_address, :from_address]
)
end
end
end

@ -9,18 +9,23 @@ defmodule Explorer.SkippedBlocks do
@missing_number_query "SELECT generate_series(?, 0, -1) AS missing_number"
def first, do: first(1)
def first(count) do
blocks = from b in Block,
blocks =
from(
b in Block,
right_join: fragment(@missing_number_query, ^latest_block_number()),
on: b.number == fragment("missing_number"),
select: fragment("missing_number::text"),
where: is_nil(b.id),
limit: ^count
)
Repo.all(blocks)
end
def latest_block_number do
block = Repo.one(Block |> Block.latest |> limit(1)) || Block.null
block = Repo.one(Block |> Block.latest() |> limit(1)) || Block.null()
block.number
end
end

@ -8,12 +8,17 @@ defmodule Explorer.SkippedReceipts do
alias Explorer.Repo.NewRelic, as: Repo
def first, do: first(1)
def first(count) do
transactions = from transaction in Transaction,
transactions =
from(
transaction in Transaction,
left_join: receipt in assoc(transaction, :receipt),
select: fragment("hash"),
where: is_nil(receipt.id),
limit: ^count
)
Repo.all(transactions)
end
end

@ -4,20 +4,21 @@ defmodule Explorer.ToAddress do
import Ecto.Changeset
use Ecto.Schema
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
@primary_key false
schema "to_addresses" do
belongs_to :transaction, Explorer.Transaction, primary_key: true
belongs_to :address, Explorer.Address
belongs_to(:transaction, Explorer.Transaction, primary_key: true)
belongs_to(:address, Explorer.Address)
timestamps()
end
def changeset(%ToAddress{} = to_address, attrs \\ %{}) do
to_address
|> cast(attrs, [:transaction_id, :address_id])
|> unique_constraint(:transaction_id,
name: :to_addresses_transaction_id_index)
|> unique_constraint(:transaction_id, name: :to_addresses_transaction_id_index)
end
end

@ -12,30 +12,32 @@ defmodule Explorer.Transaction do
alias Explorer.ToAddress
alias Explorer.Transaction
@timestamps_opts [type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}]
@timestamps_opts [
type: Timex.Ecto.DateTime,
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}
]
schema "transactions" do
has_one :receipt, Receipt
has_one :block_transaction, BlockTransaction
has_one :block, through: [:block_transaction, :block]
has_one :to_address_join, ToAddress
has_one :to_address, through: [:to_address_join, :address]
has_one :from_address_join, FromAddress
has_one :from_address, through: [:from_address_join, :address]
has_many :internal_transactions, InternalTransaction
field :hash, :string
field :value, :decimal
field :gas, :decimal
field :gas_price, :decimal
field :input, :string
field :nonce, :integer
field :public_key, :string
field :r, :string
field :s, :string
field :standard_v, :string
field :transaction_index, :string
field :v, :string
has_one(:receipt, Receipt)
has_one(:block_transaction, BlockTransaction)
has_one(:block, through: [:block_transaction, :block])
has_one(:to_address_join, ToAddress)
has_one(:to_address, through: [:to_address_join, :address])
has_one(:from_address_join, FromAddress)
has_one(:from_address, through: [:from_address_join, :address])
has_many(:internal_transactions, InternalTransaction)
field(:hash, :string)
field(:value, :decimal)
field(:gas, :decimal)
field(:gas_price, :decimal)
field(:input, :string)
field(:nonce, :integer)
field(:public_key, :string)
field(:r, :string)
field(:s, :string)
field(:standard_v, :string)
field(:transaction_index, :string)
field(:v, :string)
timestamps()
end

@ -5,11 +5,13 @@ defmodule Explorer.Workers.ImportSkippedBlocks do
@moduledoc "Imports skipped blocks."
def perform, do: perform(1)
def perform(count) do
count |> SkippedBlocks.first |> Enum.map(&ImportBlock.perform_later/1)
count |> SkippedBlocks.first() |> Enum.map(&ImportBlock.perform_later/1)
end
def perform_later, do: perform_later(1)
def perform_later(count) do
Exq.enqueue(Exq.Enqueuer, "default", __MODULE__, [count])
end

@ -8,8 +8,8 @@ defmodule Explorer.Workers.RefreshBalance do
alias Explorer.Debit
alias Explorer.Repo
def perform("credit"), do: unless refreshing("credits"), do: Credit.refresh()
def perform("debit"), do: unless refreshing("debits"), do: Debit.refresh()
def perform("credit"), do: unless(refreshing("credits"), do: Credit.refresh())
def perform("debit"), do: unless(refreshing("debits"), do: Debit.refresh())
def perform do
perform_later(["credit"])
@ -22,11 +22,10 @@ defmodule Explorer.Workers.RefreshBalance do
def refreshing(table) do
query = "REFRESH MATERIALIZED VIEW CONCURRENTLY #{table}%"
result = SQL.query!(
Repo,
"SELECT TRUE FROM pg_stat_activity WHERE query ILIKE '$#{query}'",
[]
)
result =
SQL.query!(Repo, "SELECT TRUE FROM pg_stat_activity WHERE query ILIKE '$#{query}'", [])
Enum.count(result.rows) > 0
end
end

@ -28,7 +28,8 @@ defmodule ExplorerWeb do
def view do
quote do
use Phoenix.View, root: "lib/explorer_web/templates",
use Phoenix.View,
root: "lib/explorer_web/templates",
namespace: ExplorerWeb
# Import convenience functions from controllers

@ -5,7 +5,7 @@ defmodule ExplorerWeb.UserSocket do
# channel "room:*", ExplorerWeb.RoomChannel
## Transports
transport :websocket, Phoenix.Transports.WebSocket, timeout: 45_000
transport(:websocket, Phoenix.Transports.WebSocket, timeout: 45_000)
# transport :longpoll, Phoenix.Transports.LongPoll
# Socket params are passed from the client and can

@ -9,10 +9,14 @@ defmodule ExplorerWeb.AddressController do
def show(conn, %{"id" => id}) do
hash = String.downcase(id)
query = from address in Address,
query =
from(
address in Address,
where: fragment("lower(?)", address.hash) == ^hash,
preload: [:credit, :debit],
limit: 1
)
address = Repo.one(query)
render(conn, "show.html", address: AddressForm.build(address))

@ -14,11 +14,21 @@ defmodule ExplorerWeb.AddressTransactionFromController do
def index(conn, %{"address_id" => address_id} = params) do
hash = String.downcase(address_id)
address = Repo.one(from address in Address,
address =
Repo.one(
from(
address in Address,
where: fragment("lower(?)", address.hash) == ^hash,
limit: 1)
limit: 1
)
)
address_id = address.id
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
join: block in assoc(transaction, :block),
join: receipt in assoc(transaction, :receipt),
join: from_address in assoc(transaction, :from_address),
@ -26,6 +36,8 @@ defmodule ExplorerWeb.AddressTransactionFromController do
preload: [:block, :receipt, :to_address, :from_address],
order_by: [desc: transaction.inserted_at],
where: from_address.id == ^address_id
)
page = Repo.paginate(query, params)
entries = Enum.map(page.entries, &TransactionForm.build_and_merge/1)
render(conn, "index.html", transactions: Map.put(page, :entries, entries))

@ -14,11 +14,21 @@ defmodule ExplorerWeb.AddressTransactionToController do
def index(conn, %{"address_id" => address_id} = params) do
hash = String.downcase(address_id)
address = Repo.one(from address in Address,
address =
Repo.one(
from(
address in Address,
where: fragment("lower(?)", address.hash) == ^hash,
limit: 1)
limit: 1
)
)
address_id = address.id
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
join: block in assoc(transaction, :block),
join: receipt in assoc(transaction, :receipt),
join: from_address in assoc(transaction, :from_address),
@ -26,6 +36,8 @@ defmodule ExplorerWeb.AddressTransactionToController do
preload: [:block, :receipt, :to_address, :from_address],
order_by: [desc: transaction.inserted_at],
where: to_address.id == ^address_id
)
page = Repo.paginate(query, params)
entries = Enum.map(page.entries, &TransactionForm.build_and_merge/1)
render(conn, "index.html", transactions: Map.put(page, :entries, entries))

@ -8,18 +8,24 @@ defmodule ExplorerWeb.BlockController do
alias Explorer.Repo.NewRelic, as: Repo
def index(conn, params) do
blocks = from block in Block,
blocks =
from(
block in Block,
order_by: [desc: block.number],
preload: :transactions
)
render(conn, "index.html", blocks: Repo.paginate(blocks, params))
end
def show(conn, %{"id" => number}) do
block = Block
block =
Block
|> where(number: ^number)
|> first |> Repo.one
|> BlockForm.build
|> first
|> Repo.one()
|> BlockForm.build()
render(conn, "show.html", block: block)
end
end

@ -8,7 +8,9 @@ defmodule ExplorerWeb.BlockTransactionController do
alias Explorer.TransactionForm
def index(conn, %{"block_id" => block_number} = params) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
join: block in assoc(transaction, :block),
join: receipt in assoc(transaction, :receipt),
join: from_address in assoc(transaction, :from_address),
@ -16,6 +18,8 @@ defmodule ExplorerWeb.BlockTransactionController do
preload: [:block, :receipt, :to_address, :from_address],
order_by: [desc: transaction.inserted_at],
where: block.number == ^block_number
)
page = Repo.paginate(query, params)
entries = Enum.map(page.entries, &TransactionForm.build_and_merge/1)
render(conn, "index.html", transactions: Map.put(page, :entries, entries))

@ -15,22 +15,30 @@ defmodule ExplorerWeb.ChainController do
|> put_status(:not_found)
|> put_view(ExplorerWeb.ErrorView)
|> render("404.html")
item ->
redirect_search_results(conn, item)
end
end
defp redirect_search_results(conn, %Explorer.Block{} = item) do
redirect conn, to: block_path(conn, :show, Gettext.get_locale, item.number)
redirect(conn, to: block_path(conn, :show, Gettext.get_locale(), item.number))
end
defp redirect_search_results(conn, %Explorer.Transaction{} = item) do
redirect conn, to: transaction_path(
conn, :show, Gettext.get_locale, item.hash
redirect(
conn,
to:
transaction_path(
conn,
:show,
Gettext.get_locale(),
item.hash
)
)
end
defp redirect_search_results(conn, %Explorer.Address{} = item) do
redirect conn, to: address_path(conn, :show, Gettext.get_locale, item.hash)
redirect(conn, to: address_path(conn, :show, Gettext.get_locale(), item.hash))
end
end

@ -8,8 +8,10 @@ defmodule ExplorerWeb.InternalTransactionController do
internal_transactions = Transaction.internal_transactions(hash)
render(conn,
render(
conn,
internal_transactions: internal_transactions,
transaction_hash: hash)
transaction_hash: hash
)
end
end

@ -8,7 +8,9 @@ defmodule ExplorerWeb.PendingTransactionController do
alias Explorer.PendingTransactionForm
def index(conn, %{"last_seen" => last_seen} = _) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
left_join: receipt in assoc(transaction, :receipt),
inner_join: to_address in assoc(transaction, :to_address),
inner_join: from_address in assoc(transaction, :from_address),
@ -17,26 +19,41 @@ defmodule ExplorerWeb.PendingTransactionController do
where: transaction.id < ^last_seen,
order_by: [desc: transaction.id],
limit: 10
total_query = from transaction in Transaction,
)
total_query =
from(
transaction in Transaction,
select: fragment("count(?)", transaction.id),
left_join: receipt in assoc(transaction, :receipt),
where: is_nil(receipt.transaction_id)
)
entries = Repo.all(query)
last = List.last(entries) || Transaction.null
render(conn, "index.html", transactions: %{
last = List.last(entries) || Transaction.null()
render(
conn,
"index.html",
transactions: %{
entries: entries |> Enum.map(&PendingTransactionForm.build/1),
total_entries: Repo.one(total_query),
last_seen: last.id
})
}
)
end
def index(conn, params) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
select: transaction.id,
left_join: receipt in assoc(transaction, :receipt),
where: is_nil(receipt.transaction_id),
order_by: [desc: transaction.id],
limit: 1
)
first_id = Repo.one(query) || 0
last_seen = Integer.to_string(first_id + 1)
index(conn, Map.put(params, "last_seen", last_seen))

@ -8,38 +8,59 @@ defmodule ExplorerWeb.TransactionController do
alias Explorer.TransactionForm
def index(conn, %{"last_seen" => last_seen} = _) do
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
where: transaction.id < ^last_seen,
inner_join: receipt in assoc(transaction, :receipt),
inner_join: block in assoc(transaction, :block),
inner_join: to_address in assoc(transaction, :to_address),
inner_join: from_address in assoc(transaction, :from_address),
preload: [
block: block, receipt: receipt,
to_address: to_address, from_address: from_address],
block: block,
receipt: receipt,
to_address: to_address,
from_address: from_address
],
order_by: [desc: transaction.id],
limit: 10
total_query = from transaction in Transaction,
)
total_query =
from(
transaction in Transaction,
select: fragment("count(?)", transaction.id),
inner_join: receipt in assoc(transaction, :receipt),
inner_join: block in assoc(transaction, :block)
)
entries =
query
|> Repo.all()
|> Enum.map(&TransactionForm.build_and_merge/1)
last = List.last(entries) || Transaction.null
render(conn, "index.html", transactions: %{
last = List.last(entries) || Transaction.null()
render(
conn,
"index.html",
transactions: %{
entries: entries,
total_entries: Repo.one(total_query),
last_seen: last.id
})
}
)
end
def index(conn, params) do
query = from t in Transaction,
query =
from(
t in Transaction,
select: t.id,
order_by: [desc: t.id],
limit: 1
)
first_id = Repo.one(query) || 0
last_seen = Integer.to_string(first_id + 1)
index(conn, Map.put(params, "last_seen", last_seen))
@ -47,16 +68,23 @@ defmodule ExplorerWeb.TransactionController do
def show(conn, params) do
hash = String.downcase(params["id"])
query = from transaction in Transaction,
query =
from(
transaction in Transaction,
left_join: receipt in assoc(transaction, :receipt),
left_join: block in assoc(transaction, :block),
inner_join: to_address in assoc(transaction, :to_address),
inner_join: from_address in assoc(transaction, :from_address),
preload: [
block: block, receipt: receipt,
to_address: to_address, from_address: from_address],
block: block,
receipt: receipt,
to_address: to_address,
from_address: from_address
],
where: fragment("lower(?)", transaction.hash) == ^hash,
limit: 1
)
transaction = query |> Repo.one() |> TransactionForm.build_and_merge()

@ -8,10 +8,15 @@ defmodule ExplorerWeb.TransactionLogController do
def index(conn, %{"transaction_id" => transaction_id}) do
hash = String.downcase(transaction_id)
logs = from log in Log,
logs =
from(
log in Log,
join: transaction in assoc(log, :transaction),
preload: [:address],
where: fragment("lower(?)", transaction.hash) == ^hash
)
render(conn, "index.html", logs: Repo.paginate(logs), transaction_hash: hash)
end
end

@ -2,47 +2,55 @@ defmodule ExplorerWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :explorer
if Application.get_env(:explorer, :sql_sandbox) do
plug Phoenix.Ecto.SQL.Sandbox
plug(Phoenix.Ecto.SQL.Sandbox)
end
socket "/socket", ExplorerWeb.UserSocket
socket("/socket", ExplorerWeb.UserSocket)
# Serve at "/" the static files from "priv/static" directory.
#
# You should set gzip to true if you are running phoenix.digest
# when deploying your static files in production.
plug Plug.Static,
at: "/", from: :explorer, gzip: false,
plug(
Plug.Static,
at: "/",
from: :explorer,
gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)
)
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
socket("/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket)
plug(Phoenix.LiveReloader)
plug(Phoenix.CodeReloader)
end
plug Plug.RequestId
plug Plug.Logger
plug(Plug.RequestId)
plug(Plug.Logger)
plug Plug.Parsers,
plug(
Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Poison
)
plug Plug.MethodOverride
plug Plug.Head
plug(Plug.MethodOverride)
plug(Plug.Head)
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
plug Plug.Session,
plug(
Plug.Session,
store: :cookie,
key: "_explorer_key",
signing_salt: "iC2ksJHS"
)
plug ExplorerWeb.Router
plug(ExplorerWeb.Router)
@doc """
Callback invoked for dynamically configuring the endpoint.

@ -22,9 +22,10 @@ defmodule ExplorerWeb.Gettext do
"""
use Gettext, otp_app: :explorer
@dialyzer [{:nowarn_function, 'MACRO-dgettext': 3},
{:nowarn_function, 'MACRO-dgettext': 4},
{:nowarn_function, 'MACRO-dngettext': 5},
{:nowarn_function, 'MACRO-dngettext': 6},
@dialyzer [
{:nowarn_function, "MACRO-dgettext": 3},
{:nowarn_function, "MACRO-dgettext": 4},
{:nowarn_function, "MACRO-dngettext": 5},
{:nowarn_function, "MACRO-dngettext": 6}
]
end

@ -2,11 +2,12 @@ defmodule ExplorerWeb.Router do
use ExplorerWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers, %{
plug(:accepts, ["html"])
plug(:fetch_session)
plug(:fetch_flash)
plug(:protect_from_forgery)
plug(:put_secure_browser_headers, %{
"content-security-policy" => "\
default-src 'self';\
script-src 'self' 'unsafe-inline' 'unsafe-eval';\
@ -14,67 +15,84 @@ defmodule ExplorerWeb.Router do
img-src 'self' 'unsafe-inline' 'unsafe-eval' data:;\
font-src 'self' 'unsafe-inline' 'unsafe-eval' data:;\
"
}
})
end
pipeline :set_locale do
plug SetLocale, gettext: ExplorerWeb.Gettext, default_locale: "en"
plug(SetLocale, gettext: ExplorerWeb.Gettext, default_locale: "en")
end
pipeline :exq do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :put_secure_browser_headers, %{
plug(:accepts, ["html"])
plug(:fetch_session)
plug(:fetch_flash)
plug(:put_secure_browser_headers, %{
"content-security-policy" => "\
default-src 'self';\
script-src 'self' 'unsafe-inline';\
font-src 'self' fonts.gstatic.com;\
style-src 'self' 'unsafe-inline' fonts.googleapis.com;\
"
}
plug ExqUi.RouterPlug, namespace: "exq"
})
plug(ExqUi.RouterPlug, namespace: "exq")
end
pipeline :jasmine do
if Mix.env != :prod, do: plug Jasmine, js_files: ["js/test.js"], css_files: ["css/test.css"]
if Mix.env() != :prod,
do: plug(Jasmine, js_files: ["js/test.js"], css_files: ["css/test.css"])
end
pipeline :api do
plug :accepts, ["json"]
plug(:accepts, ["json"])
end
scope "/exq", ExqUi do
pipe_through :exq
forward "/", RouterPlug.Router, :index
pipe_through(:exq)
forward("/", RouterPlug.Router, :index)
end
scope "/", ExplorerWeb do
pipe_through :browser
pipe_through :jasmine
pipe_through :set_locale
resources "/", ChainController, only: [:show], singleton: true, as: :chain
pipe_through(:browser)
pipe_through(:jasmine)
pipe_through(:set_locale)
resources("/", ChainController, only: [:show], singleton: true, as: :chain)
end
scope "/:locale", ExplorerWeb do
pipe_through :browser
pipe_through :jasmine
pipe_through :set_locale
resources "/", ChainController, only: [:show], singleton: true, as: :chain
pipe_through(:browser)
pipe_through(:jasmine)
pipe_through(:set_locale)
resources("/", ChainController, only: [:show], singleton: true, as: :chain)
resources "/blocks", BlockController, only: [:index, :show] do
resources "/transactions", BlockTransactionController, only: [:index], as: :transaction
resources("/transactions", BlockTransactionController, only: [:index], as: :transaction)
end
resources "/pending_transactions", PendingTransactionController, only: [:index]
resources("/pending_transactions", PendingTransactionController, only: [:index])
resources "/transactions", TransactionController, only: [:index, :show] do
resources "/logs", TransactionLogController, only: [:index], as: :log
resources "/internal", InternalTransactionController, only: [:index]
resources("/logs", TransactionLogController, only: [:index], as: :log)
resources("/internal", InternalTransactionController, only: [:index])
end
resources "/addresses", AddressController, only: [:show] do
resources "/transactions", AddressTransactionToController,
only: [:index], as: :transaction_to
resources "/transactions_from", AddressTransactionFromController,
only: [:index], as: :transaction_from
resources(
"/transactions",
AddressTransactionToController,
only: [:index],
as: :transaction_to
)
resources(
"/transactions_from",
AddressTransactionFromController,
only: [:index],
as: :transaction_from
)
end
get "/search", ChainController, :search
get("/search", ChainController, :search)
end
end

@ -9,8 +9,8 @@ defmodule ExplorerWeb.ErrorHelpers do
Generates tag for inlined form input errors.
"""
def error_tag(form, field) do
Enum.map(Keyword.get_values(form.errors, field), fn (error) ->
content_tag :span, translate_error(error), class: "help-block"
Enum.map(Keyword.get_values(form.errors, field), fn error ->
content_tag(:span, translate_error(error), class: "help-block")
end)
end

@ -12,6 +12,6 @@ defmodule ExplorerWeb.ErrorView do
# In case no render clause matches or no
# template is found, let's render it as 500
def template_not_found(_template, assigns) do
render "500.html", assigns
render("500.html", assigns)
end
end

@ -6,6 +6,6 @@ defmodule ExplorerWeb.TransactionView do
def format_gas_limit(gas) do
gas
|> Number.to_string!
|> Number.to_string!()
end
end

@ -7,6 +7,7 @@ defmodule Mix.Tasks.Exq.Start do
def run(["scheduler"]) do
[:postgrex, :ecto, :ethereumex, :tzdata]
|> Enum.each(&Application.ensure_all_started/1)
Repo.start_link()
Exq.start_link(mode: :enqueuer)
Scheduler.start_link()
@ -16,6 +17,7 @@ defmodule Mix.Tasks.Exq.Start do
def run(_) do
[:postgrex, :ecto, :ethereumex, :tzdata]
|> Enum.each(&Application.ensure_all_started/1)
Repo.start_link()
Exq.start_link(mode: :default)
:timer.sleep(:infinity)

@ -6,9 +6,11 @@ defmodule Mix.Tasks.Scrape.Blocks do
alias Explorer.BlockImporter
def run([]), do: run(1)
def run(count) do
[:postgrex, :ecto, :ethereumex, :tzdata]
|> Enum.each(&Application.ensure_all_started/1)
Repo.start_link()
Exq.start_link(mode: :enqueuer)

@ -7,9 +7,11 @@ defmodule Mix.Tasks.Scrape.Receipts do
alias Explorer.ReceiptImporter
def run([]), do: run(1)
def run(count) do
[:postgrex, :ecto, :ethereumex, :tzdata]
|> Enum.each(&Application.ensure_all_started/1)
Repo.start_link()
"#{count}"

@ -6,9 +6,9 @@ defmodule Explorer.Mixfile do
app: :explorer,
version: "0.0.1",
elixir: "~> 1.4",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext | Mix.compilers],
start_permanent: Mix.env == :prod,
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext | Mix.compilers()],
start_permanent: Mix.env() == :prod,
package: package(),
aliases: aliases(),
deps: deps(),
@ -26,7 +26,7 @@ defmodule Explorer.Mixfile do
def application do
[
mod: {Explorer.Application, []},
extra_applications: extra_applications(Mix.env)
extra_applications: extra_applications(Mix.env())
]
end
@ -36,12 +36,25 @@ defmodule Explorer.Mixfile do
defp elixirc_paths, do: ["lib"]
# Specifies extra applications to start per environment
defp extra_applications(:prod), do: [:phoenix_pubsub_redis, :exq, :exq_ui | extra_applications()]
defp extra_applications(:prod),
do: [:phoenix_pubsub_redis, :exq, :exq_ui | extra_applications()]
defp extra_applications(:dev), do: [:exq, :exq_ui | extra_applications()]
defp extra_applications(_), do: extra_applications()
defp extra_applications, do: [
:scrivener_ecto, :scrivener_html, :ex_cldr, :ex_jasmine, :ethereumex,
:timex, :timex_ecto, :crontab, :set_locale, :logger, :runtime_tools,
defp extra_applications,
do: [
:scrivener_ecto,
:scrivener_html,
:ex_cldr,
:ex_jasmine,
:ethereumex,
:timex,
:timex_ecto,
:crontab,
:set_locale,
:logger,
:runtime_tools,
:new_relixir
]
@ -80,11 +93,12 @@ defmodule Explorer.Mixfile do
{:react_phoenix, "~> 0.5"},
{:scrivener_ecto, "~> 1.0"},
{:scrivener_html, "~> 1.7"},
{:set_locale, github: "minifast/set_locale", branch: "master"}, # Waiting on https://github.com/smeevil/set_locale/pull/9
# Waiting on https://github.com/smeevil/set_locale/pull/9
{:set_locale, github: "minifast/set_locale", branch: "master"},
{:sobelow, ">= 0.0.0", only: [:dev, :test], runtime: false},
{:timex, "~> 3.1.24"},
{:timex_ecto, "~> 3.2.1"},
{:wallaby, "~> 0.19.2", only: [:test], runtime: false},
{:wallaby, "~> 0.19.2", only: [:test], runtime: false}
]
end
@ -98,7 +112,7 @@ defmodule Explorer.Mixfile do
[
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
"test": ["ecto.create --quiet", "ecto.migrate", "test"]
test: ["ecto.create --quiet", "ecto.migrate", "test"]
]
end

@ -18,14 +18,14 @@ defmodule Explorer.AddressTest do
describe "find_or_create_by_hash/1" do
test "that it creates a new address when one does not exist" do
Address.find_or_create_by_hash("0xFreshPrince")
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one()
assert last_address.hash == "0xfreshprince"
end
test "when the address already exists it doesn't insert a new address" do
insert(:address, %{hash: "bigmouthbillybass"})
Address.find_or_create_by_hash("bigmouthbillybass")
number_of_addresses = Address |> Repo.all |> length
number_of_addresses = Address |> Repo.all() |> length
assert number_of_addresses == 1
end

@ -17,14 +17,20 @@ defmodule Explorer.BlockTest do
test "with duplicate information" do
insert(:block, hash: "0x0")
{:error, changeset} = %Block{} |> Block.changeset(params_for(:block, hash: "0x0")) |> Repo.insert
{:error, changeset} =
%Block{} |> Block.changeset(params_for(:block, hash: "0x0")) |> Repo.insert()
refute changeset.valid?
assert changeset.errors == [hash: {"has already been taken", []}]
end
test "rejects duplicate blocks with mixed case" do
insert(:block, hash: "0xa")
{:error, changeset} = %Block{} |> Block.changeset(params_for(:block, hash: "0xA")) |> Repo.insert
{:error, changeset} =
%Block{} |> Block.changeset(params_for(:block, hash: "0xA")) |> Repo.insert()
refute changeset.valid?
assert changeset.errors == [hash: {"has already been taken", []}]
end
@ -32,7 +38,7 @@ defmodule Explorer.BlockTest do
describe "null/0" do
test "returns a block with a number of 0" do
assert Block.null.number === -1
assert Block.null().number === -1
end
end
@ -40,7 +46,9 @@ defmodule Explorer.BlockTest do
test "returns the blocks sorted by number" do
insert(:block, number: 1)
insert(:block, number: 5)
assert Block |> Block.latest |> Repo.all == Block |> order_by(desc: :number) |> Repo.all
assert Block |> Block.latest() |> Repo.all() ==
Block |> order_by(desc: :number) |> Repo.all()
end
end
end

@ -30,6 +30,7 @@ defmodule Explorer.ChainTest do
insert(:block, timestamp: time)
insert(:block, timestamp: next_time)
chain = Chain.fetch()
assert chain.average_time == %Duration{
seconds: 5,
megaseconds: 0,
@ -89,10 +90,12 @@ defmodule Explorer.ChainTest do
test "returns the last five transactions with blocks" do
block = insert(:block)
insert_list(6, :transaction)
|> Enum.map(fn (transaction) ->
|> Enum.map(fn transaction ->
insert(:block_transaction, block: block, transaction: transaction)
end)
chain = Chain.fetch()
assert chain.transactions |> Enum.count() == 5
end

@ -10,7 +10,7 @@ defmodule Explorer.CreditTest do
test "returns nothing when an address has no transactions" do
insert(:address)
Credit.refresh
Credit.refresh()
assert Repo.one(Credit) == nil
end
@ -21,9 +21,9 @@ defmodule Explorer.CreditTest do
insert(:receipt, transaction: transaction, status: 1)
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
Credit.refresh
credits = Credit |> Repo.all
assert credits |> Enum.count == 1
Credit.refresh()
credits = Credit |> Repo.all()
assert credits |> Enum.count() == 1
end
test "returns no credits to the sender" do
@ -34,8 +34,8 @@ defmodule Explorer.CreditTest do
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
address_id = sender.id
Credit.refresh
credit = Credit |> where(address_id: ^address_id) |> Repo.one
Credit.refresh()
credit = Credit |> where(address_id: ^address_id) |> Repo.one()
assert credit == nil
end
@ -47,8 +47,8 @@ defmodule Explorer.CreditTest do
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
address_id = receipient.id
Credit.refresh
credit = Credit |> where(address_id: ^address_id) |> Repo.one
Credit.refresh()
credit = Credit |> where(address_id: ^address_id) |> Repo.one()
assert credit.value == Decimal.new(21)
end
end

@ -10,7 +10,7 @@ defmodule Explorer.DebitTest do
test "returns nothing when an address has no transactions" do
insert(:address)
Debit.refresh
Debit.refresh()
assert Repo.one(Debit) == nil
end
@ -21,9 +21,9 @@ defmodule Explorer.DebitTest do
insert(:receipt, transaction: transaction, status: 1)
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
Debit.refresh
debits = Debit |> Repo.all
assert debits |> Enum.count == 1
Debit.refresh()
debits = Debit |> Repo.all()
assert debits |> Enum.count() == 1
end
test "returns a debit against the sender" do
@ -34,8 +34,8 @@ defmodule Explorer.DebitTest do
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
address_id = sender.id
Debit.refresh
debit = Debit |> where(address_id: ^address_id) |> Repo.one
Debit.refresh()
debit = Debit |> where(address_id: ^address_id) |> Repo.one()
assert debit.value == Decimal.new(21)
end
@ -47,8 +47,8 @@ defmodule Explorer.DebitTest do
insert(:from_address, transaction: transaction, address: sender)
insert(:to_address, transaction: transaction, address: receipient)
address_id = receipient.id
Debit.refresh
debit = Debit |> where(address_id: ^address_id) |> Repo.one
Debit.refresh()
debit = Debit |> where(address_id: ^address_id) |> Repo.one()
assert debit == nil
end
end

@ -16,10 +16,11 @@ defmodule Explorer.AddressFormTest do
insert(:from_address, address: sender, transaction: transaction)
insert(:to_address, address: recipient, transaction: transaction)
Credit.refresh
Debit.refresh
Credit.refresh()
Debit.refresh()
assert AddressForm.build(Repo.preload(recipient, [:debit, :credit])).balance == Decimal.new(10)
assert AddressForm.build(Repo.preload(recipient, [:debit, :credit])).balance ==
Decimal.new(10)
end
test "returns a zero balance when the address does not have balances" do

@ -16,7 +16,7 @@ defmodule Explorer.BlockFormTest do
end
test "that it returns a block's age" do
block = insert(:block, timestamp: Timex.now |> Timex.shift(hours: -1))
block = insert(:block, timestamp: Timex.now() |> Timex.shift(hours: -1))
assert BlockForm.build(block).age == "1 hour ago"
end

@ -11,15 +11,21 @@ defmodule Explorer.PendingTransactionFormTest do
transaction = insert(:transaction, inserted_at: time, updated_at: time)
insert(:to_address, address: to_address, transaction: transaction)
insert(:from_address, address: from_address, transaction: transaction)
form = PendingTransactionForm.build(transaction |> Repo.preload([:to_address, :from_address]))
assert(form == Map.merge(transaction |> Repo.preload([:to_address, :from_address]), %{
form =
PendingTransactionForm.build(transaction |> Repo.preload([:to_address, :from_address]))
assert(
form ==
Map.merge(transaction |> Repo.preload([:to_address, :from_address]), %{
to_address_hash: "0xcafe",
from_address_hash: "0xbee5",
first_seen: time |> Timex.from_now(),
last_seen: time |> Timex.from_now(),
status: :pending,
formatted_status: "Pending"
}))
})
)
end
end
end

@ -6,24 +6,34 @@ defmodule Explorer.TransactionFormTest do
describe "build/1" do
test "returns a successful transaction when there is a successful receipt" do
insert(:block, number: 24)
time = Timex.now |> Timex.shift(hours: -2)
block = insert(:block, %{
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time,
timestamp: time
})
transaction =
insert(:transaction,
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:receipt, status: 1, transaction: transaction)
form = transaction |> Repo.preload([:block, :to_address, :from_address, :receipt]) |> TransactionForm.build()
form =
transaction |> Repo.preload([:block, :to_address, :from_address, :receipt])
|> TransactionForm.build()
formatted_timestamp = block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)
assert(form == %{
assert(
form == %{
block_number: 1,
age: "2 hours ago",
formatted_age: "2 hours ago (#{formatted_timestamp})",
@ -35,31 +45,42 @@ defmodule Explorer.TransactionFormTest do
status: :success,
formatted_status: "Success",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
test "returns a failed transaction when there is a failed receipt" do
insert(:block, number: 24)
time = Timex.now |> Timex.shift(hours: -2)
block = insert(:block, %{
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time,
timestamp: time
})
transaction =
insert(:transaction,
insert(
:transaction,
gas: 155,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:receipt, status: 0, gas_used: 100, transaction: transaction)
form = transaction |> Repo.preload([:block, :to_address, :from_address, :receipt]) |> TransactionForm.build()
form =
transaction |> Repo.preload([:block, :to_address, :from_address, :receipt])
|> TransactionForm.build()
formatted_timestamp = block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)
assert(form == %{
assert(
form == %{
block_number: 1,
age: "2 hours ago",
formatted_age: "2 hours ago (#{formatted_timestamp})",
@ -71,31 +92,42 @@ defmodule Explorer.TransactionFormTest do
status: :failed,
formatted_status: "Failed",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
test "returns a out of gas transaction when the gas matches the gas used" do
insert(:block, number: 24)
time = Timex.now |> Timex.shift(hours: -2)
block = insert(:block, %{
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time,
timestamp: time
})
transaction =
insert(:transaction,
insert(
:transaction,
gas: 555,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:receipt, status: 0, gas_used: 555, transaction: transaction)
form = transaction |> Repo.preload([:block, :to_address, :from_address, :receipt]) |> TransactionForm.build()
form =
transaction |> Repo.preload([:block, :to_address, :from_address, :receipt])
|> TransactionForm.build()
formatted_timestamp = block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)
assert(form == %{
assert(
form == %{
block_number: 1,
age: "2 hours ago",
formatted_age: "2 hours ago (#{formatted_timestamp})",
@ -107,29 +139,37 @@ defmodule Explorer.TransactionFormTest do
status: :out_of_gas,
formatted_status: "Out of Gas",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
test "returns a pending transaction when there is no receipt" do
insert(:block, number: 24)
time = Timex.now |> Timex.shift(hours: -2)
block = insert(:block, %{
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time,
timestamp: time
})
transaction =
insert(:transaction,
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
|> Repo.preload([:block, :to_address, :from_address, :receipt])
form = TransactionForm.build(transaction)
formatted_timestamp = block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)
assert(form == %{
assert(
form == %{
block_number: 1,
age: "2 hours ago",
formatted_age: "2 hours ago (#{formatted_timestamp})",
@ -141,20 +181,25 @@ defmodule Explorer.TransactionFormTest do
status: :pending,
formatted_status: "Pending",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
test "returns a pending transaction when there is no block" do
transaction = insert(
transaction =
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> with_addresses(%{to: "0xchadmuska", from: "0xtonyhawk"})
|> Repo.preload([:to_address, :from_address])
form = TransactionForm.build(transaction)
assert(form == %{
assert(
form == %{
block_number: "",
age: "Pending",
formatted_age: "Pending",
@ -166,19 +211,24 @@ defmodule Explorer.TransactionFormTest do
status: :pending,
formatted_status: "Pending",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
test "works when there are no addresses" do
transaction = insert(
transaction =
insert(
:transaction,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"))
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
|> Repo.preload([:block, :to_address, :from_address])
form = TransactionForm.build(transaction)
assert(form == %{
assert(
form == %{
block_number: "",
age: "Pending",
formatted_age: "Pending",
@ -190,31 +240,40 @@ defmodule Explorer.TransactionFormTest do
status: :pending,
formatted_status: "Pending",
first_seen: "48 years ago",
last_seen: "38 years ago",
})
last_seen: "38 years ago"
}
)
end
end
describe "build_and_merge/1" do
test "it returns a merged map of a transaction and its built data" do
insert(:block, number: 24)
time = Timex.now |> Timex.shift(hours: -2)
block = insert(:block, %{
time = Timex.now() |> Timex.shift(hours: -2)
block =
insert(:block, %{
number: 1,
gas_used: 99523,
timestamp: time,
timestamp: time
})
transaction =
insert(:transaction,
insert(
:transaction,
hash: "0xkittenpower",
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}"),
gas: 555)
gas: 555
)
|> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:receipt, status: 0, gas_used: 555, transaction: transaction)
form = transaction |> Repo.preload([:block, :to_address, :from_address, :receipt]) |> TransactionForm.build_and_merge()
form =
transaction |> Repo.preload([:block, :to_address, :from_address, :receipt])
|> TransactionForm.build_and_merge()
assert form.hash == "0xkittenpower"
assert form.block_number == 1

@ -11,23 +11,35 @@ defmodule Explorer.BlockImporterTest do
describe "import/1" do
test "imports and saves a block to the database" do
use_cassette "block_importer_import_1_saves_the_block" do
with_mock ImportTransaction, [perform: fn(_) -> {:ok} end] do
with_mock ImportTransaction, perform: fn _ -> {:ok} end do
BlockImporter.import("0xc4f0d")
block = Block |> order_by(desc: :inserted_at) |> Repo.one()
assert block.hash == "0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e"
assert block.hash ==
"0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e"
end
end
end
test "when a block with the same hash is imported it does not update the block" do
use_cassette "block_importer_import_1_duplicate_block" do
with_mock ImportTransaction, [perform: fn(hash) -> insert(:transaction, hash: hash) end] do
insert(:block, hash: "0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e", gas_limit: 5)
with_mock ImportTransaction, perform: fn hash -> insert(:transaction, hash: hash) end do
insert(
:block,
hash: "0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e",
gas_limit: 5
)
BlockImporter.import("0xc4f0d")
block = Repo.get_by(Block, hash: "0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e")
block =
Repo.get_by(
Block,
hash: "0x16cb43ccfb7875c14eb3f03bdc098e4af053160544270594fa429d256cbca64e"
)
assert block.gas_limit == 5
assert Block |> Repo.all |> Enum.count == 1
assert Block |> Repo.all() |> Enum.count() == 1
end
end
end
@ -36,18 +48,18 @@ defmodule Explorer.BlockImporterTest do
describe "import/1 pending" do
test "does not create a block" do
use_cassette "block_importer_import_1_pending" do
with_mock ImportTransaction, [perform_later: fn(_) -> {:ok} end] do
with_mock ImportTransaction, perform_later: fn _ -> {:ok} end do
BlockImporter.import("pending")
assert Block |> Repo.all |> Enum.count == 0
assert Block |> Repo.all() |> Enum.count() == 0
end
end
end
test "when a block with the same hash is imported does not create a block" do
use_cassette "block_importer_import_1_pending" do
with_mock ImportTransaction, [perform_later: fn(_) -> insert(:transaction) end] do
with_mock ImportTransaction, perform_later: fn _ -> insert(:transaction) end do
BlockImporter.import("pending")
assert Transaction |> Repo.all |> Enum.count != 0
assert Transaction |> Repo.all() |> Enum.count() != 0
end
end
end
@ -75,7 +87,8 @@ defmodule Explorer.BlockImporterTest do
describe "extract_block/1" do
test "extracts the block attributes" do
extracted_block = BlockImporter.extract_block(%{
extracted_block =
BlockImporter.extract_block(%{
"difficulty" => "0xfffffffffffffffffffffffffffffffe",
"gasLimit" => "0x02",
"gasUsed" => "0x19522",
@ -90,25 +103,27 @@ defmodule Explorer.BlockImporterTest do
"transactions" => []
})
assert(extracted_block == %{
difficulty: 340282366920938463463374607431768211454,
assert(
extracted_block == %{
difficulty: 340_282_366_920_938_463_463_374_607_431_768_211_454,
gas_limit: 2,
gas_used: 103714,
gas_used: 103_714,
hash: "bananas",
nonce: "0xfb6e1a62d119228b",
miner: "0xdb1207770e0a4258d7a4ce49ab037f92564fea85",
number: 520955,
number: 520_955,
parent_hash: "0x70029f66ea5a3b2b1ede95079d95a2ab74b649b5b17cdcf6f29b6317e7c7efa6",
size: 16,
timestamp: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
total_difficulty: 255,
})
total_difficulty: 255
}
)
end
end
describe "decode_integer_field/1" do
test "returns the integer value of a hex value" do
assert(BlockImporter.decode_integer_field("0x7f2fb") == 520955)
assert(BlockImporter.decode_integer_field("0x7f2fb") == 520_955)
end
end

@ -7,7 +7,12 @@ defmodule Explorer.InternalTransactionImporterTest do
describe "import/1" do
test "imports and saves an internal transaction to the database" do
use_cassette "internal_transaction_importer_import_1" do
transaction = insert(:transaction, hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68")
transaction =
insert(
:transaction,
hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68"
)
InternalTransactionImporter.import(transaction.hash)
internal_transactions = InternalTransaction |> Repo.all()
assert length(internal_transactions) == 2
@ -16,18 +21,34 @@ defmodule Explorer.InternalTransactionImporterTest do
test "imports internal transactions with ordered indexes" do
use_cassette "internal_transaction_importer_import_1" do
transaction = insert(:transaction, hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68")
transaction =
insert(
:transaction,
hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68"
)
InternalTransactionImporter.import(transaction.hash)
last_internal_transaction = InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one()
last_internal_transaction =
InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one()
assert last_internal_transaction.index == 1
end
end
test "imports an internal transaction that creates a contract" do
use_cassette "internal_transaction_importer_import_1_with_contract_creation" do
transaction = insert(:transaction, hash: "0x27d64b8e8564d2852c88767e967b88405c99341509cd3a3504fd67a65277116d")
transaction =
insert(
:transaction,
hash: "0x27d64b8e8564d2852c88767e967b88405c99341509cd3a3504fd67a65277116d"
)
InternalTransactionImporter.import(transaction.hash)
last_internal_transaction = InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one()
last_internal_transaction =
InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one()
assert last_internal_transaction.call_type == "create"
end
end
@ -47,7 +68,7 @@ defmodule Explorer.InternalTransactionImporterTest do
"gas" => "0x4821f",
"input" => "0xd1f276d3",
"to" => "0xe213402e637565bb9de0651827517e7554693f53",
"value" => "0x0",
"value" => "0x0"
},
"result" => %{
"gasUsed" => "0x4e4",
@ -61,18 +82,20 @@ defmodule Explorer.InternalTransactionImporterTest do
to_address = insert(:address, hash: "0xe213402e637565bb9de0651827517e7554693f53")
from_address = insert(:address, hash: "0xba9f067abbc4315ece8eb33e7a3d01030bb368ef")
assert(InternalTransactionImporter.extract_trace({trace, 2}) == %{
assert(
InternalTransactionImporter.extract_trace({trace, 2}) == %{
index: 2,
to_address_id: to_address.id,
from_address_id: from_address.id,
call_type: "call",
trace_address: [2, 0],
value: 0,
gas: 295455,
gas: 295_455,
gas_used: 1252,
input: "0xd1f276d3",
output: "0x000000000000000000000000ba9f067abbc4315ece8eb33e7a3d01030bb368ef",
})
output: "0x000000000000000000000000ba9f067abbc4315ece8eb33e7a3d01030bb368ef"
}
)
end
end
end

@ -7,72 +7,128 @@ defmodule Explorer.ReceiptImporterTest do
describe "import/1" do
test "saves a receipt to the database" do
transaction = insert(:transaction, hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
transaction =
insert(
:transaction,
hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
use_cassette "transaction_importer_import_1_receipt" do
ReceiptImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
receipt = Receipt |> preload([:transaction]) |> Repo.one
ReceiptImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
receipt = Receipt |> preload([:transaction]) |> Repo.one()
assert receipt.transaction == transaction
end
end
test "saves a receipt log" do
insert(:transaction, hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
insert(
:transaction,
hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
use_cassette "transaction_importer_import_1_receipt" do
ReceiptImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
receipt = Receipt |> preload([:transaction]) |> Repo.one
log = Log |> preload([receipt: :transaction]) |> Repo.one
ReceiptImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
receipt = Receipt |> preload([:transaction]) |> Repo.one()
log = Log |> preload(receipt: :transaction) |> Repo.one()
assert log.receipt == receipt
end
end
test "saves a receipt log for an address" do
insert(:transaction, hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
insert(
:transaction,
hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
address = insert(:address, hash: "0x353fe3ffbf77edef7f9c352c47965a38c07e837c")
use_cassette "transaction_importer_import_1_receipt" do
ReceiptImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
log = Log |> preload([:address]) |> Repo.one
ReceiptImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
log = Log |> preload([:address]) |> Repo.one()
assert log.address == address
end
end
test "saves a receipt for a failed transaction" do
insert(:transaction, hash: "0x2532864dc2e0d0bc2dfabf4685c0c03dbdbe9cf67ebc593fc82d41087ab71435")
insert(
:transaction,
hash: "0x2532864dc2e0d0bc2dfabf4685c0c03dbdbe9cf67ebc593fc82d41087ab71435"
)
use_cassette "transaction_importer_import_1_failed" do
ReceiptImporter.import("0x2532864dc2e0d0bc2dfabf4685c0c03dbdbe9cf67ebc593fc82d41087ab71435")
ReceiptImporter.import(
"0x2532864dc2e0d0bc2dfabf4685c0c03dbdbe9cf67ebc593fc82d41087ab71435"
)
receipt = Repo.one(Receipt)
assert receipt.status == 0
end
end
test "saves a receipt for a transaction that ran out of gas" do
insert(:transaction, hash: "0x702e518267b0a57e4cb44b9db100afe4d7115f2d2650466a8c376f3dbb77eb35")
insert(
:transaction,
hash: "0x702e518267b0a57e4cb44b9db100afe4d7115f2d2650466a8c376f3dbb77eb35"
)
use_cassette "transaction_importer_import_1_out_of_gas" do
ReceiptImporter.import("0x702e518267b0a57e4cb44b9db100afe4d7115f2d2650466a8c376f3dbb77eb35")
ReceiptImporter.import(
"0x702e518267b0a57e4cb44b9db100afe4d7115f2d2650466a8c376f3dbb77eb35"
)
receipt = Repo.one(Receipt)
assert receipt.status == 0
end
end
test "does not import a receipt for a transaction that already has one" do
transaction = insert(:transaction, hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
transaction =
insert(
:transaction,
hash: "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
insert(:receipt, transaction: transaction)
use_cassette "transaction_importer_import_1_receipt" do
ReceiptImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
ReceiptImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
assert Repo.all(Receipt) |> Enum.count() == 1
end
end
test "does not import a receipt for a nonexistent transaction" do
use_cassette "transaction_importer_import_1_receipt" do
ReceiptImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
ReceiptImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
assert Repo.all(Receipt) |> Enum.count() == 0
end
end
test "does not process a forever-pending receipt" do
insert(:transaction, hash: "0xde791cfcde3900d4771e5fcf8c11dc305714118df7aa7e42f84576e64dbf6246")
insert(
:transaction,
hash: "0xde791cfcde3900d4771e5fcf8c11dc305714118df7aa7e42f84576e64dbf6246"
)
use_cassette "transaction_importer_import_1_pending" do
ReceiptImporter.import("0xde791cfcde3900d4771e5fcf8c11dc305714118df7aa7e42f84576e64dbf6246")
ReceiptImporter.import(
"0xde791cfcde3900d4771e5fcf8c11dc305714118df7aa7e42f84576e64dbf6246"
)
assert Repo.all(Receipt) |> Enum.count() == 0
end
end

@ -23,39 +23,51 @@ defmodule Explorer.TransactionImporterTest do
"to" => "0x7a33b7d",
"standardV" => "0x11",
"transactionIndex" => "0x12",
"v" => "0x13",
"v" => "0x13"
}
@processed_transaction %{
hash: "pepino",
value: 1000000000000000000,
gas: 135168,
value: 1_000_000_000_000_000_000,
gas: 135_168,
gas_price: 65536,
input: "0x5c8eff12",
nonce: 201527,
nonce: 201_527,
public_key: "0xb39af9c",
r: "0x9",
s: "0x10",
standard_v: "0x11",
transaction_index: "0x12",
v: "0x13",
v: "0x13"
}
describe "import/1" do
test "imports and saves a transaction to the database" do
use_cassette "transaction_importer_import_saves_the_transaction" do
TransactionImporter.import("0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291")
transaction = Transaction |> order_by(desc: :inserted_at) |> Repo.one
TransactionImporter.import(
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
)
assert transaction.hash == "0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
transaction = Transaction |> order_by(desc: :inserted_at) |> Repo.one()
assert transaction.hash ==
"0xdc3a0dfd0bbffd5eabbe40fb13afbe35ac5f5c030bff148f3e50afe32974b291"
end
end
test "when the transaction has previously been saved does not update it" do
use_cassette "transaction_importer_updates_the_association" do
insert(:transaction, hash: "0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23", gas: 5)
TransactionImporter.import("0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23")
transaction = Transaction |> order_by(desc: :inserted_at) |> Repo.one
insert(
:transaction,
hash: "0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23",
gas: 5
)
TransactionImporter.import(
"0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23"
)
transaction = Transaction |> order_by(desc: :inserted_at) |> Repo.one()
assert transaction.gas == Decimal.new(5)
end
@ -63,9 +75,22 @@ defmodule Explorer.TransactionImporterTest do
test "binds an association to an existing block" do
use_cassette "transaction_importer_saves_the_association" do
block = insert(:block, hash: "0xfce13392435a8e7dab44c07d482212efb9dc39a9bea1915a9ead308b55a617f9")
TransactionImporter.import("0x64d851139325479c3bb7ccc6e6ab4cde5bc927dce6810190fe5d770a4c1ac333")
transaction = Transaction |> Repo.get_by(hash: "0x64d851139325479c3bb7ccc6e6ab4cde5bc927dce6810190fe5d770a4c1ac333")
block =
insert(
:block,
hash: "0xfce13392435a8e7dab44c07d482212efb9dc39a9bea1915a9ead308b55a617f9"
)
TransactionImporter.import(
"0x64d851139325479c3bb7ccc6e6ab4cde5bc927dce6810190fe5d770a4c1ac333"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0x64d851139325479c3bb7ccc6e6ab4cde5bc927dce6810190fe5d770a4c1ac333"
)
block_transaction = BlockTransaction |> Repo.get_by(transaction_id: transaction.id)
assert block_transaction.block_id == block.id
@ -74,8 +99,16 @@ defmodule Explorer.TransactionImporterTest do
test "when there is no block it does not save a block transaction" do
use_cassette "transaction_importer_txn_without_block" do
TransactionImporter.import("0xc6aa189827c14880f012a65292f7add7b5310094f8773a3d85b66303039b9dcf")
transaction = Transaction |> Repo.get_by(hash: "0xc6aa189827c14880f012a65292f7add7b5310094f8773a3d85b66303039b9dcf")
TransactionImporter.import(
"0xc6aa189827c14880f012a65292f7add7b5310094f8773a3d85b66303039b9dcf"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xc6aa189827c14880f012a65292f7add7b5310094f8773a3d85b66303039b9dcf"
)
block_transaction = BlockTransaction |> Repo.get_by(transaction_id: transaction.id)
refute block_transaction
@ -84,11 +117,20 @@ defmodule Explorer.TransactionImporterTest do
test "creates a from address" do
use_cassette "transaction_importer_creates_a_from_address" do
TransactionImporter.import("0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d")
TransactionImporter.import(
"0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d"
)
transaction = Transaction |> Repo.get_by(hash: "0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d")
address = Address |> Repo.get_by(hash: "0xa5b4b372112ab8dbbb48c8d0edd89227e24ec785")
from_address = FromAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
from_address =
FromAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
assert from_address
end
@ -96,12 +138,22 @@ defmodule Explorer.TransactionImporterTest do
test "binds an existing from address" do
insert(:address, hash: "0xa5b4b372112ab8dbbb48c8d0edd89227e24ec785")
use_cassette "transaction_importer_creates_a_from_address" do
TransactionImporter.import("0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d")
TransactionImporter.import(
"0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d"
)
transaction = Transaction |> Repo.get_by(hash: "0xc445f5410912458c480d992dd93355ae3dad64d9f65db25a3cf43a9c609a2e0d")
address = Address |> Repo.get_by(hash: "0xa5b4b372112ab8dbbb48c8d0edd89227e24ec785")
from_address = FromAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
from_address =
FromAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
assert from_address
end
@ -109,11 +161,20 @@ defmodule Explorer.TransactionImporterTest do
test "creates a to address" do
use_cassette "transaction_importer_creates_a_to_address" do
TransactionImporter.import("0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
TransactionImporter.import(
"0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
transaction = Transaction |> Repo.get_by(hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
address = Address |> Repo.get_by(hash: "0x24e5b8528fe83257d5fe3497ef616026713347f8")
to_address = ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
to_address =
ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
assert(to_address)
end
@ -121,12 +182,22 @@ defmodule Explorer.TransactionImporterTest do
test "binds an existing to address" do
insert(:address, hash: "0x24e5b8528fe83257d5fe3497ef616026713347f8")
use_cassette "transaction_importer_creates_a_to_address" do
TransactionImporter.import("0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
TransactionImporter.import(
"0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
transaction = Transaction |> Repo.get_by(hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
address = Address |> Repo.get_by(hash: "0x24e5b8528fe83257d5fe3497ef616026713347f8")
to_address = ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
to_address =
ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
assert(to_address)
end
@ -134,10 +205,20 @@ defmodule Explorer.TransactionImporterTest do
test "creates a to address using creates when to is nil" do
use_cassette "transaction_importer_creates_a_to_address_from_creates" do
TransactionImporter.import("0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
transaction = Transaction |> Repo.get_by(hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c")
TransactionImporter.import(
"0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
transaction =
Transaction
|> Repo.get_by(
hash: "0xdc533d4227734a7cacd75a069e8dc57ac571b865ed97bae5ea4cb74b54145f4c"
)
address = Address |> Repo.get_by(hash: "0x24e5b8528fe83257d5fe3497ef616026713347f8")
to_address = ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
to_address =
ToAddress |> Repo.get_by(transaction_id: transaction.id, address_id: address.id)
assert(to_address)
end
@ -145,7 +226,11 @@ defmodule Explorer.TransactionImporterTest do
test "processes a map of transaction attributes" do
insert(:block, hash: "0xtakis")
TransactionImporter.import(Map.merge(@raw_transaction, %{"hash" => "0xmunchos", "blockHash" => "0xtakis"}))
TransactionImporter.import(
Map.merge(@raw_transaction, %{"hash" => "0xmunchos", "blockHash" => "0xtakis"})
)
last_transaction = Transaction |> order_by(desc: :inserted_at) |> limit(1) |> Repo.one()
assert last_transaction.hash == "0xmunchos"
@ -166,7 +251,11 @@ defmodule Explorer.TransactionImporterTest do
describe "download_transaction/1" do
test "downloads a transaction" do
use_cassette "transaction_importer_download_transaction" do
raw_transaction = TransactionImporter.download_transaction("0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23")
raw_transaction =
TransactionImporter.download_transaction(
"0x170baac4eca26076953370dd603c68eab340c0135b19b585010d3158a5dbbf23"
)
assert(raw_transaction["from"] == "0xbe96ef1d056c97323e210fd0dd818aa027e57143")
end
end
@ -192,6 +281,7 @@ defmodule Explorer.TransactionImporterTest do
block = insert(:block)
transaction = insert(:transaction)
TransactionImporter.create_block_transaction(transaction, block.hash)
block_transaction =
BlockTransaction
|> Repo.get_by(transaction_id: transaction.id, block_id: block.id)
@ -203,9 +293,18 @@ defmodule Explorer.TransactionImporterTest do
block = insert(:block)
transaction = insert(:transaction)
the_seventies = Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}")
block_transaction = insert(:block_transaction, %{block_id: block.id, transaction_id: transaction.id, inserted_at: the_seventies, updated_at: the_seventies})
block_transaction =
insert(:block_transaction, %{
block_id: block.id,
transaction_id: transaction.id,
inserted_at: the_seventies,
updated_at: the_seventies
})
update_block = insert(:block)
TransactionImporter.create_block_transaction(transaction, update_block.hash)
updated_block_transaction =
BlockTransaction
|> Repo.get_by(transaction_id: transaction.id)
@ -219,7 +318,7 @@ defmodule Explorer.TransactionImporterTest do
test "that it creates a new address when one does not exist" do
transaction = insert(:transaction)
TransactionImporter.create_from_address(transaction, "0xbb8")
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one()
assert last_address.hash == "0xbb8"
end
@ -227,8 +326,8 @@ defmodule Explorer.TransactionImporterTest do
test "that it joins transaction and from address" do
transaction = insert(:transaction)
TransactionImporter.create_from_address(transaction, "0xFreshPrince")
address = Address |> order_by(desc: :inserted_at) |> Repo.one
from_address = FromAddress |> order_by(desc: :inserted_at) |> Repo.one
address = Address |> order_by(desc: :inserted_at) |> Repo.one()
from_address = FromAddress |> order_by(desc: :inserted_at) |> Repo.one()
assert from_address.transaction_id == transaction.id
assert from_address.address_id == address.id
@ -239,7 +338,7 @@ defmodule Explorer.TransactionImporterTest do
insert(:address, hash: "0xbb8")
TransactionImporter.create_from_address(transaction, "0xbb8")
assert Address |> Repo.all |> length == 1
assert Address |> Repo.all() |> length == 1
end
end
@ -247,7 +346,7 @@ defmodule Explorer.TransactionImporterTest do
test "that it creates a new address when one does not exist" do
transaction = insert(:transaction)
TransactionImporter.create_to_address(transaction, "0xFreshPrince")
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one
last_address = Address |> order_by(desc: :inserted_at) |> Repo.one()
assert last_address.hash == "0xfreshprince"
end
@ -255,8 +354,8 @@ defmodule Explorer.TransactionImporterTest do
test "that it joins transaction and address" do
transaction = insert(:transaction)
TransactionImporter.create_to_address(transaction, "0xFreshPrince")
address = Address |> order_by(desc: :inserted_at) |> Repo.one
to_address = ToAddress |> order_by(desc: :inserted_at) |> Repo.one
address = Address |> order_by(desc: :inserted_at) |> Repo.one()
to_address = ToAddress |> order_by(desc: :inserted_at) |> Repo.one()
assert to_address.transaction_id == transaction.id
assert to_address.address_id == address.id
@ -267,13 +366,13 @@ defmodule Explorer.TransactionImporterTest do
insert(:address, hash: "bigmouthbillybass")
TransactionImporter.create_to_address(transaction, "bigmouthbillybass")
assert Address |> Repo.all |> length == 1
assert Address |> Repo.all() |> length == 1
end
end
describe "decode_integer_field/1" do
test "returns the integer value of a hex value" do
assert(TransactionImporter.decode_integer_field("0x7f2fb") == 520955)
assert(TransactionImporter.decode_integer_field("0x7f2fb") == 520_955)
end
end
end

@ -6,7 +6,22 @@ defmodule Explorer.InternalTransactionTest do
describe "changeset/2" do
test "with valid attributes" do
transaction = insert(:transaction)
changeset = InternalTransaction.changeset(%InternalTransaction{}, %{transaction_id: transaction.id, index: 0, call_type: "call", trace_address: [0, 1], value: 100, gas: 100, gas_used: 100, input: "pintos", output: "refried", to_address_id: 1, from_address_id: 2})
changeset =
InternalTransaction.changeset(%InternalTransaction{}, %{
transaction_id: transaction.id,
index: 0,
call_type: "call",
trace_address: [0, 1],
value: 100,
gas: 100,
gas_used: 100,
input: "pintos",
output: "refried",
to_address_id: 1,
from_address_id: 2
})
assert changeset.valid?
end
@ -17,7 +32,20 @@ defmodule Explorer.InternalTransactionTest do
test "that a valid changeset is persistable" do
transaction = insert(:transaction)
changeset = InternalTransaction.changeset(%InternalTransaction{}, %{transaction: transaction, index: 0, call_type: "call", trace_address: [0, 1], value: 100, gas: 100, gas_used: 100, input: "thin-mints", output: "munchos"})
changeset =
InternalTransaction.changeset(%InternalTransaction{}, %{
transaction: transaction,
index: 0,
call_type: "call",
trace_address: [0, 1],
value: 100,
gas: 100,
gas_used: 100,
input: "thin-mints",
output: "munchos"
})
assert Repo.insert(changeset)
end
end

@ -33,7 +33,7 @@ defmodule Explorer.ReceiptTest do
log_params = params_for(:log, address: address)
params = params_for(:receipt, transaction: transaction, logs: [log_params])
changeset = Receipt.changeset(%Receipt{}, params)
receipt = Repo.insert!(changeset) |> Repo.preload([logs: :address])
receipt = Repo.insert!(changeset) |> Repo.preload(logs: :address)
assert List.first(receipt.logs).address == address
end
end

@ -5,7 +5,22 @@ defmodule Explorer.TransactionTest do
describe "changeset/2" do
test "with valid attributes" do
changeset = Transaction.changeset(%Transaction{}, %{hash: "0x0", value: 1, gas: 21000, gas_price: 10000, input: "0x5c8eff12", nonce: "31337", public_key: "0xb39af9c", r: "0x9", s: "0x10", standard_v: "0x11", transaction_index: "0x12", v: "0x13"})
changeset =
Transaction.changeset(%Transaction{}, %{
hash: "0x0",
value: 1,
gas: 21000,
gas_price: 10000,
input: "0x5c8eff12",
nonce: "31337",
public_key: "0xb39af9c",
r: "0x9",
s: "0x10",
standard_v: "0x11",
transaction_index: "0x12",
v: "0x13"
})
assert changeset.valid?
end

@ -11,7 +11,7 @@ defmodule Explorer.Workers.ImportBlockTest do
test "imports the requested block number as an integer" do
use_cassette "import_block_perform_1_integer" do
ImportBlock.perform(1)
last_block = Block |> order_by(asc: :number) |> Repo.one
last_block = Block |> order_by(asc: :number) |> Repo.one()
assert last_block.number == 1
end
end
@ -19,7 +19,7 @@ defmodule Explorer.Workers.ImportBlockTest do
test "imports the requested block number as a string" do
use_cassette "import_block_perform_1_string" do
ImportBlock.perform("1")
last_block = Block |> order_by(asc: :number) |> Repo.one
last_block = Block |> order_by(asc: :number) |> Repo.one()
assert last_block.number == 1
end
end
@ -27,16 +27,16 @@ defmodule Explorer.Workers.ImportBlockTest do
test "imports the earliest block" do
use_cassette "import_block_perform_1_earliest" do
ImportBlock.perform("earliest")
last_block = Block |> order_by(asc: :number) |> Repo.one
last_block = Block |> order_by(asc: :number) |> Repo.one()
assert last_block.number == 0
end
end
test "imports the latest block" do
use_cassette "import_block_perform_1_latest" do
with_mock Exq, [enqueue: fn (_, _, _, [number]) -> insert(:block, number: number) end] do
with_mock Exq, enqueue: fn _, _, _, [number] -> insert(:block, number: number) end do
ImportBlock.perform("latest")
last_block = Block |> order_by(asc: :number) |> Repo.one
last_block = Block |> order_by(asc: :number) |> Repo.one()
assert last_block.number > 0
end
end
@ -46,7 +46,7 @@ defmodule Explorer.Workers.ImportBlockTest do
use_cassette "import_block_perform_1_duplicate" do
insert(:block, hash: "0x52c867bc0a91e573dc39300143c3bead7408d09d45bdb686749f02684ece72f3")
ImportBlock.perform("1")
block_count = Block |> Repo.all |> Enum.count
block_count = Block |> Repo.all() |> Enum.count()
assert block_count == 1
end
end
@ -55,9 +55,9 @@ defmodule Explorer.Workers.ImportBlockTest do
describe "perform_later/1" do
test "does not retry fetching the latest block" do
use_cassette "import_block_perform_later_1_latest" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> insert(:block, number: 1) end] do
with_mock Exq, enqueue: fn _, _, _, _ -> insert(:block, number: 1) end do
ImportBlock.perform_later("latest")
last_block = Block |> order_by(asc: :number) |> limit(1) |> Repo.one
last_block = Block |> order_by(asc: :number) |> limit(1) |> Repo.one()
assert last_block.number == 1
end
end

@ -8,16 +8,26 @@ defmodule Explorer.Workers.ImportReceiptTest do
describe "perform/1" do
test "does not import a receipt when no transaction with the hash exists" do
use_cassette "import_receipt_perform_1" do
ImportReceipt.perform("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
ImportReceipt.perform(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
assert Repo.one(Receipt) == nil
end
end
test "imports a receipt when a transaction with the hash exists" do
insert(:transaction, hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
insert(
:transaction,
hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
use_cassette "import_receipt_perform_1" do
ImportReceipt.perform("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
receipt_count = Receipt |> Repo.all |> Enum.count
ImportReceipt.perform(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
receipt_count = Receipt |> Repo.all() |> Enum.count()
assert receipt_count == 1
end
end

@ -11,10 +11,11 @@ defmodule Explorer.Workers.ImportSkippedBlocksTest do
describe "perform/1" do
test "imports the requested number of skipped blocks" do
insert(:block, %{number: 2})
use_cassette "import_skipped_blocks_perform_1" do
with_mock ImportBlock, [perform_later: fn (number) -> insert(:block, number: number) end] do
with_mock ImportBlock, perform_later: fn number -> insert(:block, number: number) end do
ImportSkippedBlocks.perform(1)
last_block = Block |> order_by(asc: :number) |> limit(1) |> Repo.one
last_block = Block |> order_by(asc: :number) |> limit(1) |> Repo.one()
assert last_block.number == 1
end
end

@ -11,30 +11,50 @@ defmodule Explorer.Workers.ImportTransactionTest do
describe "perform/1" do
test "imports the requested transaction hash" do
use_cassette "import_transaction_perform_1" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> :ok end] do
ImportTransaction.perform("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
with_mock Exq, enqueue: fn _, _, _, _ -> :ok end do
ImportTransaction.perform(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
end
transaction = Transaction |> Repo.one
assert transaction.hash == "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
transaction = Transaction |> Repo.one()
assert transaction.hash ==
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
end
end
test "when there is already a transaction with the requested hash" do
insert(:transaction, hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
insert(
:transaction,
hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
use_cassette "import_transaction_perform_1" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> :ok end] do
ImportTransaction.perform("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
with_mock Exq, enqueue: fn _, _, _, _ -> :ok end do
ImportTransaction.perform(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
end
transaction_count = Transaction |> Repo.all |> Enum.count
transaction_count = Transaction |> Repo.all() |> Enum.count()
assert transaction_count == 1
end
end
test "imports the receipt in another queue" do
transaction = insert(:transaction, hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
transaction =
insert(
:transaction,
hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
use_cassette "import_transaction_perform_1" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> insert(:receipt, transaction: transaction) end] do
ImportTransaction.perform("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
with_mock Exq, enqueue: fn _, _, _, _ -> insert(:receipt, transaction: transaction) end do
ImportTransaction.perform(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
receipt = Repo.one(Receipt)
refute is_nil(receipt)
end
@ -42,15 +62,21 @@ defmodule Explorer.Workers.ImportTransactionTest do
end
test "imports the receipt in another queue when a map is supplied" do
transaction = insert(:transaction, hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
transaction =
insert(
:transaction,
hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
use_cassette "import_transaction_perform_1" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> insert(:receipt, transaction: transaction) end] do
with_mock Exq, enqueue: fn _, _, _, _ -> insert(:receipt, transaction: transaction) end do
ImportTransaction.perform(%{
"hash" => "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926",
"to" => "0xc001",
"from" => "0xbead5",
"blockHash" => "0xcafe",
"blockHash" => "0xcafe"
})
receipt = Repo.one(Receipt)
refute is_nil(receipt)
end
@ -61,10 +87,21 @@ defmodule Explorer.Workers.ImportTransactionTest do
describe "perform_later/1" do
test "imports the transaction in another queue" do
use_cassette "import_transaction_perform_1" do
with_mock Exq, [enqueue: fn (_, _, _, _) -> insert(:transaction, hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926") end] do
ImportTransaction.perform_later("0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926")
with_mock Exq,
enqueue: fn _, _, _, _ ->
insert(
:transaction,
hash: "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
end do
ImportTransaction.perform_later(
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
)
transaction = Repo.one(Transaction)
assert transaction.hash == "0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
assert transaction.hash ==
"0xf9a0959d5ccde33ec5221ddba1c6d7eaf9580a8d3512c7a1a60301362a98f926"
end
end
end

@ -9,23 +9,23 @@ defmodule Explorer.Workers.RefreshBalanceTest do
describe "perform/0" do
test "refreshes credit balances" do
with_mock Exq, [enqueue: fn (_, _, _, [type]) -> RefreshBalance.perform(type) end] do
with_mock Exq, enqueue: fn _, _, _, [type] -> RefreshBalance.perform(type) end do
address = insert(:address)
transaction = insert(:transaction, value: 20)
insert(:to_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform
RefreshBalance.perform()
assert Repo.one(Credit).value == Decimal.new(20)
end
end
test "refreshes debit balances" do
with_mock Exq, [enqueue: fn (_, _, _, [type]) -> RefreshBalance.perform(type) end] do
with_mock Exq, enqueue: fn _, _, _, [type] -> RefreshBalance.perform(type) end do
address = insert(:address)
transaction = insert(:transaction, value: 20)
insert(:from_address, address: address, transaction: transaction)
insert(:receipt, transaction: transaction, status: 1)
RefreshBalance.perform
RefreshBalance.perform()
assert Repo.one(Debit).value == Decimal.new(20)
end
end

@ -7,8 +7,8 @@ defmodule ExplorerWeb.AddressControllerTest do
describe "GET show/3" do
test "returns an address", %{conn: conn} do
address = insert(:address, hash: "0x9")
Credit.refresh
Debit.refresh
Credit.refresh()
Debit.refresh()
conn = get(conn, "/en/addresses/0x9")
assert conn.assigns.address.id == address.id
end

@ -13,7 +13,10 @@ defmodule ExplorerWeb.AddressTransactionFromControllerTest do
other_address = insert(:address)
insert(:to_address, transaction: transaction, address: other_address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 1
assert List.first(conn.assigns.transactions.entries).hash == "0xsnacks"
end
@ -27,7 +30,10 @@ defmodule ExplorerWeb.AddressTransactionFromControllerTest do
other_address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
insert(:from_address, transaction: transaction, address: other_address)
conn = get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -38,7 +44,10 @@ defmodule ExplorerWeb.AddressTransactionFromControllerTest do
address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -49,7 +58,10 @@ defmodule ExplorerWeb.AddressTransactionFromControllerTest do
insert(:block_transaction, transaction: transaction, block: block)
address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -60,7 +72,10 @@ defmodule ExplorerWeb.AddressTransactionFromControllerTest do
insert(:block_transaction, transaction: transaction, block: block)
address = insert(:address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_from_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
end

@ -13,7 +13,10 @@ defmodule ExplorerWeb.AddressTransactionToControllerTest do
other_address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
insert(:from_address, transaction: transaction, address: other_address)
conn = get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 1
assert List.first(conn.assigns.transactions.entries).hash == "0xsnacks"
end
@ -27,7 +30,10 @@ defmodule ExplorerWeb.AddressTransactionToControllerTest do
other_address = insert(:address)
insert(:to_address, transaction: transaction, address: other_address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -38,7 +44,10 @@ defmodule ExplorerWeb.AddressTransactionToControllerTest do
address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -49,7 +58,10 @@ defmodule ExplorerWeb.AddressTransactionToControllerTest do
insert(:block_transaction, transaction: transaction, block: block)
address = insert(:address)
insert(:to_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
@ -60,7 +72,10 @@ defmodule ExplorerWeb.AddressTransactionToControllerTest do
insert(:block_transaction, transaction: transaction, block: block)
address = insert(:address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
conn =
get(conn, address_transaction_to_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
assert conn.assigns.transactions.total_entries == 0
end
end

@ -11,9 +11,11 @@ defmodule ExplorerWeb.BlockControllerTest do
describe "GET index/2" do
test "returns all blocks", %{conn: conn} do
block_ids = insert_list(4, :block) |> Enum.map(fn (block) -> block.number end) |> Enum.reverse
block_ids =
insert_list(4, :block) |> Enum.map(fn block -> block.number end) |> Enum.reverse()
conn = get(conn, "/en/blocks")
assert conn.assigns.blocks |> Enum.map(fn (block) -> block.number end) == block_ids
assert conn.assigns.blocks |> Enum.map(fn block -> block.number end) == block_ids
end
test "returns a block with two transactions", %{conn: conn} do
@ -23,7 +25,7 @@ defmodule ExplorerWeb.BlockControllerTest do
other_transaction = insert(:transaction)
insert(:block_transaction, block: block, transaction: other_transaction)
conn = get(conn, "/en/blocks")
assert conn.assigns.blocks.entries |> Enum.count == 1
assert conn.assigns.blocks.entries |> Enum.count() == 1
end
end
end

@ -1,11 +1,12 @@
defmodule ExplorerWeb.ChainControllerTest do
use ExplorerWeb.ConnCase
import ExplorerWeb.Router.Helpers, only: [chain_path: 3, block_path: 4, transaction_path: 4, address_path: 4]
import ExplorerWeb.Router.Helpers,
only: [chain_path: 3, block_path: 4, transaction_path: 4, address_path: 4]
describe "GET index/2 without a locale" do
test "redirects to the en locale", %{conn: conn} do
conn = get conn, "/"
conn = get(conn, "/")
assert(redirected_to(conn) == "/en")
end
@ -13,14 +14,14 @@ defmodule ExplorerWeb.ChainControllerTest do
describe "GET index/2 with a locale" do
test "returns a welcome message", %{conn: conn} do
conn = get conn, chain_path(ExplorerWeb.Endpoint, :show, %{locale: :en})
conn = get(conn, chain_path(ExplorerWeb.Endpoint, :show, %{locale: :en}))
assert(html_response(conn, 200) =~ "POA")
end
test "returns a block", %{conn: conn} do
insert(:block, %{number: 23})
conn = get conn, "/en"
conn = get(conn, "/en")
assert(List.first(conn.assigns.chain.blocks).number == 23)
end
@ -28,18 +29,23 @@ defmodule ExplorerWeb.ChainControllerTest do
test "excludes all but the most recent five blocks", %{conn: conn} do
old_block = insert(:block)
insert_list(5, :block)
conn = get conn, "/en"
conn = get(conn, "/en")
refute(Enum.member?(conn.assigns.chain.blocks, old_block))
end
test "only returns transactions with an associated block", %{conn: conn} do
block = insert(:block, number: 33)
insert(:transaction, id: 10, hash: "0xDECAFBAD") |> with_block(block) |> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:transaction, id: 10, hash: "0xDECAFBAD") |> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
insert(:transaction, id: 30)
conn = get conn, "/en"
transaction_ids = conn.assigns.chain.transactions
|> Enum.map(fn (transaction) -> transaction.id end)
conn = get(conn, "/en")
transaction_ids =
conn.assigns.chain.transactions
|> Enum.map(fn transaction -> transaction.id end)
assert(Enum.member?(transaction_ids, 10))
refute(Enum.member?(transaction_ids, 30))
@ -47,8 +53,11 @@ defmodule ExplorerWeb.ChainControllerTest do
test "returns a transaction", %{conn: conn} do
block = insert(:block, number: 33)
insert(:transaction, hash: "0xDECAFBAD") |> with_block(block) |> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
conn = get conn, "/en"
insert(:transaction, hash: "0xDECAFBAD") |> with_block(block)
|> with_addresses(%{to: "0xsleepypuppy", from: "0xilovefrogs"})
conn = get(conn, "/en")
assert(List.first(conn.assigns.chain.transactions).hash == "0xDECAFBAD")
end
@ -57,27 +66,27 @@ defmodule ExplorerWeb.ChainControllerTest do
describe "GET q/2" do
test "finds a block by block number", %{conn: conn} do
insert(:block, number: 37)
conn = get conn, "/en/search?q=37"
conn = get(conn, "/en/search?q=37")
assert redirected_to(conn) == block_path(conn, :show, "en", "37")
end
test "finds a transaction by hash", %{conn: conn} do
transaction = insert(:transaction) |> with_block() |> with_addresses
conn = get conn, "/en/search?q=#{transaction.hash}"
conn = get(conn, "/en/search?q=#{transaction.hash}")
assert redirected_to(conn) == transaction_path(conn, :show, "en", transaction.hash)
end
test "finds an address by hash", %{conn: conn} do
address = insert(:address)
conn = get conn, "en/search?q=#{address.hash}"
conn = get(conn, "en/search?q=#{address.hash}")
assert redirected_to(conn) == address_path(conn, :show, "en", address.hash)
end
test "redirects to 404 when it finds nothing", %{conn: conn} do
conn = get conn, "en/search?q=zaphod"
conn = get(conn, "en/search?q=zaphod")
assert conn.status == 404
end
end

@ -51,7 +51,14 @@ defmodule ExplorerWeb.PendingTransactionControllerTest do
transaction = insert(:transaction)
insert(:to_address, transaction: transaction, address: address)
insert(:from_address, transaction: transaction, address: address)
conn = get(conn, pending_transaction_path(ExplorerWeb.Endpoint, :index, :en), last_seen: transaction.id)
conn =
get(
conn,
pending_transaction_path(ExplorerWeb.Endpoint, :index, :en),
last_seen: transaction.id
)
assert conn.assigns.transactions.entries == []
end
end

@ -52,7 +52,9 @@ defmodule ExplorerWeb.TransactionControllerTest do
end
describe "GET show/3" do
test "when there is an associated block, it returns a transaction with block data", %{conn: conn} do
test "when there is an associated block, it returns a transaction with block data", %{
conn: conn
} do
block = insert(:block, %{number: 777})
transaction = insert(:transaction, hash: "0x8") |> with_block(block) |> with_addresses
conn = get(conn, "/en/transactions/0x8")

@ -29,11 +29,15 @@ defmodule ExplorerWeb.UserListTest do
end
test "search for transactions", %{session: session} do
insert(:transaction, hash: "0xdeadbeef000000000000000000000000000000000", input: "socks") |> with_addresses()
insert(:transaction, hash: "0xdeadbeef000000000000000000000000000000000", input: "socks")
|> with_addresses()
session
|> visit("/")
|> fill_in(css(".header__cell--search-input"), with: "0xdeadbeef000000000000000000000000000000000")
|> fill_in(
css(".header__cell--search-input"),
with: "0xdeadbeef000000000000000000000000000000000"
)
|> send_keys([:enter])
|> assert_has(css(".transaction__item", text: "socks"))
end
@ -43,30 +47,42 @@ defmodule ExplorerWeb.UserListTest do
session
|> visit("/")
|> fill_in(css(".header__cell--search-input"), with: "0xBAADF00D00000000000000000000000000000000")
|> fill_in(
css(".header__cell--search-input"),
with: "0xBAADF00D00000000000000000000000000000000"
)
|> send_keys([:enter])
|> assert_has(css(".address__subheading", text: "0xBAADF00D00000000000000000000000000000000"))
end
test "views blocks", %{session: session} do
insert_list(4, :block, %{number: 1, timestamp: Timex.now |> Timex.shift(hours: -1), gas_used: 10})
fifth_block = insert(:block, %{
insert_list(4, :block, %{
number: 1,
timestamp: Timex.now() |> Timex.shift(hours: -1),
gas_used: 10
})
fifth_block =
insert(:block, %{
number: 311,
hash: "0xMrCoolBlock",
timestamp: Timex.now |> Timex.shift(hours: -1),
timestamp: Timex.now() |> Timex.shift(hours: -1),
miner: "Heathcliff",
size: 9999999,
size: 9_999_999,
nonce: "once upon a nonce",
gas_used: 1010101,
gas_limit: 5030101
gas_used: 1_010_101,
gas_limit: 5_030_101
})
transaction = insert(:transaction, hash: "0xfaschtnacht") |> with_block(fifth_block) |> with_addresses
transaction =
insert(:transaction, hash: "0xfaschtnacht") |> with_block(fifth_block) |> with_addresses
insert(:transaction, hash: "0xpaczki") |> with_block(fifth_block) |> with_addresses
insert(:transaction) |> with_block(fifth_block) |> with_addresses
insert(:receipt, transaction: transaction)
Credit.refresh
Debit.refresh
Credit.refresh()
Debit.refresh()
session
|> visit("/en")
@ -80,7 +96,6 @@ defmodule ExplorerWeb.UserListTest do
session
|> click(link("Blocks"))
|> assert_has(css(".blocks__column--height", text: "311"))
|> click(link("311"))
|> assert_has(css(".block__item", text: "0xMrCoolBlock"))
|> assert_has(css(".block__item", text: "Heathcliff"))
@ -89,32 +104,37 @@ defmodule ExplorerWeb.UserListTest do
|> assert_has(css(".block__item", text: "5,030,101"))
|> assert_has(css(".block__item", text: "once upon a nonce"))
|> assert_has(css(".block__item", text: "1,010,101"))
|> click(css(".block__link", text: "Transactions"))
|> assert_has(css(".transactions__link--long-hash", text: "0xfaschtnacht"))
end
test "views transactions", %{session: session} do
block = insert(:block, %{
block =
insert(:block, %{
number: 555,
timestamp: Timex.now |> Timex.shift(hours: -2),
gas_used: 123987,
timestamp: Timex.now() |> Timex.shift(hours: -2),
gas_used: 123_987
})
for _ <- 0..3, do: insert(:transaction) |> with_block(block) |> with_addresses
insert(:transaction, hash: "0xC001", gas: 5891) |> with_block |> with_addresses
lincoln = insert(:address, hash: "0xlincoln")
taft = insert(:address, hash: "0xhowardtaft")
transaction = insert(:transaction,
transaction =
insert(
:transaction,
hash: "0xSk8",
value: 5656,
gas: 1230000000000123123,
gas_price: 7890000000898912300045,
gas: 1_230_000_000_000_123_123,
gas_price: 7_890_000_000_898_912_300_045,
input: "0x00012",
nonce: 99045,
inserted_at: Timex.parse!("1970-01-01T00:00:18-00:00", "{ISO:Extended}"),
updated_at: Timex.parse!("1980-01-01T00:00:18-00:00", "{ISO:Extended}")
)
insert(:block_transaction, block: block, transaction: transaction)
insert(:from_address, address: taft, transaction: transaction)
insert(:to_address, address: lincoln, transaction: transaction)
@ -130,8 +150,8 @@ defmodule ExplorerWeb.UserListTest do
internal = insert(:internal_transaction, transaction_id: transaction.id)
Credit.refresh
Debit.refresh
Credit.refresh()
Debit.refresh()
session
|> visit("/en")
@ -139,15 +159,12 @@ defmodule ExplorerWeb.UserListTest do
|> assert_has(css(".transactions__column--hash", count: 5))
|> assert_has(css(".transactions__column--value", count: 5))
|> assert_has(css(".transactions__column--age", count: 5, visible: false))
|> visit("/transactions")
|> click(css(".transactions__tab-link", text: "Pending"))
|> click(css(".transactions__link", text: "0xC001"))
|> assert_has(css(".transaction__item-value--status", text: "Pending"))
|> visit("/transactions")
|> refute_has(css(".transactions__column--block", text: "Pending"))
|> click(link("0xSk8"))
|> assert_has(css(".transaction__subheading", text: "0xSk8"))
|> assert_has(css(".transaction__item", text: "123,987"))
@ -163,20 +180,15 @@ defmodule ExplorerWeb.UserListTest do
|> assert_has(css(".transaction__item", text: "block confirmations"))
|> assert_has(css(".transaction__item", text: "48 years ago"))
|> assert_has(css(".transaction__item", text: "38 years ago"))
|> click(link("Internal Transactions"))
|> assert_has(css(".internal-transaction__table", text: internal.call_type))
|> visit("/en/transactions/0xSk8")
|> click(link("Logs"))
|> assert_has(css(".transaction-log__link", text: "0xlincoln"))
|> click(link("0xlincoln"))
|> assert_has(css(".address__subheading", text: "0xlincoln"))
|> click(css(".address__link", text: "Transactions To"))
|> assert_has(css(".transactions__link--long-hash", text: "0xSk8"))
|> click(css(".address__link", text: "Transactions From"))
|> assert_has(css(".transactions__link--long-hash", text: "0xrazerscooter"))
end

@ -5,17 +5,14 @@ defmodule ExplorerWeb.ErrorViewTest do
import Phoenix.View
test "renders 404.html" do
assert render_to_string(ExplorerWeb.ErrorView, "404.html", []) ==
"Page not found"
assert render_to_string(ExplorerWeb.ErrorView, "404.html", []) == "Page not found"
end
test "render 500.html" do
assert render_to_string(ExplorerWeb.ErrorView, "500.html", []) ==
"Internal server error"
assert render_to_string(ExplorerWeb.ErrorView, "500.html", []) == "Internal server error"
end
test "render any other" do
assert render_to_string(ExplorerWeb.ErrorView, "505.html", []) ==
"Internal server error"
assert render_to_string(ExplorerWeb.ErrorView, "505.html", []) == "Internal server error"
end
end

@ -25,13 +25,13 @@ defmodule ExplorerWeb.ChannelCase do
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, {:shared, self()})
end
:ok
end
end

@ -31,9 +31,11 @@ defmodule ExplorerWeb.ConnCase do
@dialyzer {:nowarn_function, __ex_unit_setup_0: 1}
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, {:shared, self()})
end
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
end

@ -13,7 +13,7 @@ defmodule Explorer.BlockFactory do
size: Enum.random(1..100_000),
gas_limit: Enum.random(1..100_000),
gas_used: Enum.random(1..100_000),
timestamp: DateTime.utc_now,
timestamp: DateTime.utc_now()
}
end
end

@ -13,7 +13,7 @@ defmodule Explorer.InternalTransactionFactory do
gas: Enum.random(1..100_000),
gas_used: Enum.random(1..100_000),
input: sequence("0x"),
output: sequence("0x"),
output: sequence("0x")
}
end
end

@ -9,7 +9,7 @@ defmodule Explorer.LogFactory do
first_topic: nil,
second_topic: nil,
third_topic: nil,
fourth_topic: nil,
fourth_topic: nil
}
end
end

@ -6,7 +6,7 @@ defmodule Explorer.ReceiptFactory do
cumulative_gas_used: Enum.random(21_000..100_000),
gas_used: Enum.random(21_000..100_000),
status: Enum.random(1..2),
index: sequence(""),
index: sequence("")
}
end
end

@ -18,13 +18,21 @@ defmodule Explorer.TransactionFactory do
s: sequence("0x"),
standard_v: sequence("0x"),
transaction_index: sequence("0x"),
v: sequence("0x"),
v: sequence("0x")
}
end
def with_addresses(transaction, %{to: to, from: from} \\ %{to: nil, from: nil}) do
to_address = if to, do: Repo.get_by(Address, %{hash: to}) || insert(:address, hash: to), else: insert(:address)
from_address = if from, do: Repo.get_by(Address, %{hash: from}) ||insert(:address, hash: from), else: insert(:address)
to_address =
if to,
do: Repo.get_by(Address, %{hash: to}) || insert(:address, hash: to),
else: insert(:address)
from_address =
if from,
do: Repo.get_by(Address, %{hash: from}) || insert(:address, hash: from),
else: insert(:address)
insert(:to_address, %{transaction_id: transaction.id, address_id: to_address.id})
insert(:from_address, %{transaction_id: transaction.id, address_id: from_address.id})
transaction
@ -37,7 +45,7 @@ defmodule Explorer.TransactionFactory do
end
def list_with_block(transactions, block \\ nil) do
Enum.map(transactions, fn(transaction) -> with_block(transaction, block) end)
Enum.map(transactions, fn transaction -> with_block(transaction, block) end)
end
end
end

@ -1,8 +1,8 @@
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start
ExUnit.start()
{:ok, _} = Application.ensure_all_started(:wallaby)
Application.put_env(:wallaby, :base_url, ExplorerWeb.Endpoint.url)
Application.put_env(:wallaby, :base_url, ExplorerWeb.Endpoint.url())
{:ok, _} = Application.ensure_all_started(:ex_machina)

Loading…
Cancel
Save