Land #128: Replace form modules with proper view module functions
commit
3e55171fac
@ -0,0 +1,10 @@ |
||||
defmodule Explorer.Chain.Gas do |
||||
@moduledoc """ |
||||
A measurement roughly equivalent to computational steps. Every operation has a gas expenditure; for most operations |
||||
it is ~3-10, although some expensive operations have expenditures up to 700 and a transaction itself has an |
||||
expenditure of 21000. |
||||
""" |
||||
|
||||
@typedoc @moduledoc |
||||
@type t :: non_neg_integer() |
||||
end |
@ -0,0 +1,105 @@ |
||||
defmodule Explorer.Chain.Wei do |
||||
@moduledoc """ |
||||
The smallest fractional unit of Ether. Using wei instead of ether allows code to do integer match instead of using |
||||
floats. |
||||
|
||||
Etymology of "wei" comes from [Wei Dai (戴維)](https://en.wikipedia.org/wiki/Wei_Dai), a |
||||
[cypherpunk](https://en.wikipedia.org/wiki/Cypherpunk) who came up with b-money, which outlined modern |
||||
cryptocurrencies. |
||||
""" |
||||
|
||||
@typedoc """ |
||||
Ether is the default unit Ethereum and its side chains are measured in when displaying values to humans. |
||||
|
||||
10<sup>18</sup> wei is 1 ether. |
||||
""" |
||||
@type ether :: Decimal.t() |
||||
|
||||
@typedoc """ |
||||
Short for giga-wei |
||||
|
||||
* 10<sup>9</sup> wei is one gwei |
||||
""" |
||||
@type gwei :: Decimal.t() |
||||
|
||||
@typedoc """ |
||||
The unit to convert `t:wei/0` to. |
||||
""" |
||||
@type unit :: :wei | :gwei | :ether |
||||
|
||||
@typedoc @moduledoc |
||||
@type t :: Decimal.t() |
||||
|
||||
# Constants |
||||
|
||||
@wei_per_ether Decimal.new(1_000_000_000_000_000_000) |
||||
@wei_per_gwei Decimal.new(1_000_000_000) |
||||
|
||||
## Functions |
||||
|
||||
@doc """ |
||||
Convert wei to itself. |
||||
|
||||
iex> Explorer.Chain.Wei.from(Decimal.new(1), :wei) |
||||
Decimal.new(1) |
||||
|
||||
Convert `t:gwei/0` to wei. |
||||
|
||||
iex> Explorer.Chain.Wei.from(Decimal.new(1), :gwei) |
||||
Decimal.new(1_000_000_000) |
||||
|
||||
Convert `t:ether/0` to wei. |
||||
|
||||
iex> Explorer.Chain.Wei.from(Decimal.new(1), :ether) |
||||
Decimal.new(1_000_000_000_000_000_000) |
||||
|
||||
""" |
||||
|
||||
@spec from(ether(), :ether) :: t() |
||||
def from(ether, :ether) do |
||||
Decimal.mult(ether, @wei_per_ether) |
||||
end |
||||
|
||||
@spec from(gwei(), :gwei) :: t() |
||||
def from(gwei, :gwei) do |
||||
Decimal.mult(gwei, @wei_per_gwei) |
||||
end |
||||
|
||||
@spec from(t(), :wei) :: t() |
||||
def from(wei, :wei), do: wei |
||||
|
||||
@doc """ |
||||
Convert wei to itself. |
||||
|
||||
iex> Explorer.Chain.Wei.to(Decimal.new(1), :wei) |
||||
Decimal.new(1) |
||||
|
||||
Convert wei to `t:gwei/0`. |
||||
|
||||
iex> Explorer.Chain.Wei.to(Decimal.new(1), :gwei) |
||||
Decimal.new("1e-9") |
||||
iex> Explorer.Chain.Wei.to(Decimal.new("1e9"), :gwei) |
||||
Decimal.new(1) |
||||
|
||||
Convert wei to `t:ether/0`. |
||||
|
||||
iex> Explorer.Chain.Wei.to(Decimal.new(1), :ether) |
||||
Decimal.new("1e-18") |
||||
iex> Explorer.Chain.Wei.to(Decimal.new("1e18"), :ether) |
||||
Decimal.new(1) |
||||
|
||||
""" |
||||
|
||||
@spec to(t(), :ether) :: ether() |
||||
def to(wei, :ether) do |
||||
Decimal.div(wei, @wei_per_ether) |
||||
end |
||||
|
||||
@spec to(t(), :gwei) :: gwei() |
||||
def to(wei, :gwei) do |
||||
Decimal.div(wei, @wei_per_gwei) |
||||
end |
||||
|
||||
@spec to(t(), :wei) :: t() |
||||
def to(wei, :wei), do: wei |
||||
end |
@ -0,0 +1,5 @@ |
||||
defmodule Explorer.Chain.WeiTest do |
||||
use ExUnit.Case, async: true |
||||
|
||||
doctest Explorer.Chain.Wei |
||||
end |
@ -1,22 +0,0 @@ |
||||
defmodule ExplorerWeb.BlockForm do |
||||
@moduledoc false |
||||
|
||||
alias Explorer.Chain |
||||
|
||||
def build(block) do |
||||
block |
||||
|> Map.merge(%{ |
||||
age: calculate_age(block), |
||||
formatted_timestamp: format_timestamp(block), |
||||
transactions_count: Chain.block_to_transaction_count(block) |
||||
}) |
||||
end |
||||
|
||||
def calculate_age(block) do |
||||
block.timestamp |> Timex.from_now() |
||||
end |
||||
|
||||
def format_timestamp(block) do |
||||
block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime) |
||||
end |
||||
end |
@ -1,42 +0,0 @@ |
||||
defmodule ExplorerWeb.PendingTransactionForm do |
||||
@moduledoc "Format a pending Transaction for display." |
||||
|
||||
import ExplorerWeb.Gettext |
||||
|
||||
alias Explorer.Chain.{Address, Transaction} |
||||
|
||||
# Functions |
||||
|
||||
def build(transaction) do |
||||
Map.merge(transaction, %{ |
||||
first_seen: first_seen(transaction), |
||||
formatted_status: gettext("Pending"), |
||||
from_address_hash: from_address_hash(transaction), |
||||
last_seen: last_seen(transaction), |
||||
status: :pending, |
||||
to_address_hash: to_address_hash(transaction) |
||||
}) |
||||
end |
||||
|
||||
def first_seen(transaction) do |
||||
transaction.inserted_at |> Timex.from_now() |
||||
end |
||||
|
||||
def from_address_hash(%Transaction{from_address: from_address}) do |
||||
case from_address do |
||||
%Address{hash: hash} -> hash |
||||
_ -> nil |
||||
end |
||||
end |
||||
|
||||
def last_seen(transaction) do |
||||
transaction.updated_at |> Timex.from_now() |
||||
end |
||||
|
||||
def to_address_hash(%Transaction{to_address: to_address}) do |
||||
case to_address do |
||||
%Address{hash: hash} -> hash |
||||
_ -> nil |
||||
end |
||||
end |
||||
end |
@ -1,112 +0,0 @@ |
||||
defmodule ExplorerWeb.TransactionForm do |
||||
@moduledoc "Format a Block and a Transaction for display." |
||||
|
||||
import ExplorerWeb.Gettext |
||||
|
||||
alias Cldr.Number |
||||
alias Explorer.Chain |
||||
alias Explorer.Chain.{Receipt, Transaction} |
||||
|
||||
def build(transaction) do |
||||
block = block(transaction) |
||||
receipt = receipt(transaction) |
||||
status = status(transaction, receipt || Receipt.null()) |
||||
|
||||
%{ |
||||
block_number: block |> block_number, |
||||
age: block |> block_age, |
||||
formatted_age: block |> format_age, |
||||
formatted_timestamp: block |> format_timestamp, |
||||
cumulative_gas_used: block |> cumulative_gas_used, |
||||
to_address_hash: transaction |> to_address_hash, |
||||
from_address_hash: transaction |> from_address_hash, |
||||
confirmations: block |> confirmations, |
||||
status: status, |
||||
formatted_status: status |> format_status, |
||||
first_seen: transaction |> first_seen, |
||||
last_seen: transaction |> last_seen |
||||
} |
||||
end |
||||
|
||||
def build_and_merge(transaction) do |
||||
Map.merge(transaction, build(transaction)) |
||||
end |
||||
|
||||
def block(%Transaction{block: block}) do |
||||
if Ecto.assoc_loaded?(block) do |
||||
block |
||||
else |
||||
nil |
||||
end |
||||
end |
||||
|
||||
def block_age(block) do |
||||
(block && block.timestamp |> Timex.from_now()) || gettext("Pending") |
||||
end |
||||
|
||||
def block_number(block) do |
||||
(block && block.number) || "" |
||||
end |
||||
|
||||
def confirmations(nil), do: 0 |
||||
|
||||
def confirmations(block) do |
||||
Chain.confirmations(block, max_block_number: Chain.max_block_number()) |
||||
end |
||||
|
||||
def cumulative_gas_used(block) do |
||||
(block && block.gas_used |> Number.to_string!()) || gettext("Pending") |
||||
end |
||||
|
||||
def first_seen(transaction) do |
||||
transaction.inserted_at |> Timex.from_now() |
||||
end |
||||
|
||||
def format_age(block) do |
||||
(block && "#{block_age(block)} (#{format_timestamp(block)})") || gettext("Pending") |
||||
end |
||||
|
||||
def format_status(status) do |
||||
%{ |
||||
out_of_gas: gettext("Out of Gas"), |
||||
failed: gettext("Failed"), |
||||
success: gettext("Success"), |
||||
pending: gettext("Pending") |
||||
} |
||||
|> Map.fetch!(status) |
||||
end |
||||
|
||||
def format_timestamp(block) do |
||||
(block && block.timestamp |> Timex.format!("%b-%d-%Y %H:%M:%S %p %Z", :strftime)) || |
||||
gettext("Pending") |
||||
end |
||||
|
||||
def from_address_hash(transaction) do |
||||
(transaction.to_address && transaction.from_address.hash) || nil |
||||
end |
||||
|
||||
def last_seen(transaction) do |
||||
transaction.updated_at |> Timex.from_now() |
||||
end |
||||
|
||||
def receipt(%Transaction{receipt: receipt}) do |
||||
if Ecto.assoc_loaded?(receipt) do |
||||
receipt |
||||
else |
||||
nil |
||||
end |
||||
end |
||||
|
||||
def status(transaction, receipt) do |
||||
%{ |
||||
0 => %{true => :out_of_gas, false => :failed}, |
||||
1 => %{true => :success, false => :success} |
||||
} |
||||
|> Map.get(receipt.status, %{true: :pending, false: :pending}) |
||||
|> Map.get(receipt.gas_used == transaction.gas) |
||||
end |
||||
|
||||
def to_address_hash(transaction) do |
||||
(transaction.to_address && transaction.to_address.hash) || nil |
||||
end |
||||
end |
@ -1,20 +0,0 @@ |
||||
defmodule ExplorerWeb.WeiConverter do |
||||
@moduledoc """ |
||||
Utility module for conversion of wei to other units |
||||
""" |
||||
|
||||
@wei_per_ether 1_000_000_000_000_000_000 |
||||
@wei_per_gwei 1_000_000_000 |
||||
|
||||
@spec to_ether(Decimal.t()) :: Decimal.t() |
||||
def to_ether(wei) do |
||||
wei |
||||
|> Decimal.div(Decimal.new(@wei_per_ether)) |
||||
end |
||||
|
||||
@spec to_gwei(Decimal.t()) :: Decimal.t() |
||||
def to_gwei(wei) do |
||||
wei |
||||
|> Decimal.div(Decimal.new(@wei_per_gwei)) |
||||
end |
||||
end |
@ -1,4 +1,8 @@ |
||||
defmodule ExplorerWeb.AddressTransactionFromView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
|
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
defdelegate status(transacton), to: TransactionView |
||||
defdelegate value(transaction), to: TransactionView |
||||
end |
||||
|
@ -1,4 +1,8 @@ |
||||
defmodule ExplorerWeb.AddressTransactionToView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
|
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
defdelegate status(transacton), to: TransactionView |
||||
defdelegate value(transaction), to: TransactionView |
||||
end |
||||
|
@ -1,4 +1,10 @@ |
||||
defmodule ExplorerWeb.BlockTransactionView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
|
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
# Functions |
||||
|
||||
defdelegate status(transacton), to: TransactionView |
||||
defdelegate value(transaction), to: TransactionView |
||||
end |
||||
|
@ -1,4 +1,17 @@ |
||||
defmodule ExplorerWeb.BlockView do |
||||
use ExplorerWeb, :view |
||||
|
||||
alias Explorer.Chain.Block |
||||
|
||||
@dialyzer :no_match |
||||
|
||||
# Functions |
||||
|
||||
def age(%Block{timestamp: timestamp}) do |
||||
Timex.from_now(timestamp) |
||||
end |
||||
|
||||
def formatted_timestamp(%Block{timestamp: timestamp}) do |
||||
Timex.format!(timestamp, "%b-%d-%Y %H:%M:%S %p %Z", :strftime) |
||||
end |
||||
end |
||||
|
@ -1,4 +1,7 @@ |
||||
defmodule ExplorerWeb.ChainView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
|
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
defdelegate value(transaction), to: TransactionView |
||||
end |
||||
|
@ -1,4 +1,28 @@ |
||||
defmodule ExplorerWeb.PendingTransactionView do |
||||
use ExplorerWeb, :view |
||||
|
||||
alias Explorer.Chain.{Address, Transaction} |
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
@dialyzer :no_match |
||||
|
||||
# Functions |
||||
|
||||
def from_address_hash(%Transaction{from_address: from_address}) do |
||||
case from_address do |
||||
%Address{hash: hash} -> hash |
||||
_ -> nil |
||||
end |
||||
end |
||||
|
||||
defdelegate last_seen(transaction), to: TransactionView |
||||
|
||||
def to_address_hash(%Transaction{to_address: to_address}) do |
||||
case to_address do |
||||
%Address{hash: hash} -> hash |
||||
_ -> nil |
||||
end |
||||
end |
||||
|
||||
defdelegate value(transaction), to: TransactionView |
||||
end |
||||
|
@ -1,30 +0,0 @@ |
||||
defmodule ExplorerWeb.BlockFormTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias ExplorerWeb.BlockForm |
||||
|
||||
describe "build/1" do |
||||
test "that it has a number" do |
||||
block = insert(:block, number: 311) |
||||
insert_list(2, :transaction) |> list_with_block(block) |
||||
assert BlockForm.build(block).number == 311 |
||||
end |
||||
|
||||
test "that it returns a count of transactions" do |
||||
block = insert(:block, number: 311) |
||||
insert_list(2, :transaction) |> list_with_block(block) |
||||
assert BlockForm.build(block).transactions_count == 2 |
||||
end |
||||
|
||||
test "that it returns a block's age" do |
||||
block = insert(:block, timestamp: Timex.now() |> Timex.shift(hours: -1)) |
||||
assert BlockForm.build(block).age == "1 hour ago" |
||||
end |
||||
|
||||
test "formats a timestamp" do |
||||
date = "Jan-23-2018 10:48:56 AM Etc/UTC" |
||||
block = insert(:block, timestamp: Timex.parse!(date, "%b-%d-%Y %H:%M:%S %p %Z", :strftime)) |
||||
assert BlockForm.build(block).formatted_timestamp == date |
||||
end |
||||
end |
||||
end |
@ -1,37 +0,0 @@ |
||||
defmodule ExplorerWeb.PendingTransactionFormTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias ExplorerWeb.PendingTransactionForm |
||||
|
||||
describe "build/1" do |
||||
test "returns a successful transaction when there is a successful receipt" do |
||||
time = DateTime.utc_now() |
||||
to_address = insert(:address, hash: "0xcafe") |
||||
from_address = insert(:address, hash: "0xbee5") |
||||
|
||||
transaction = |
||||
insert( |
||||
:transaction, |
||||
inserted_at: time, |
||||
updated_at: time, |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|
||||
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 |
@ -1,308 +0,0 @@ |
||||
defmodule ExplorerWeb.TransactionFormTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias ExplorerWeb.TransactionForm |
||||
|
||||
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, %{ |
||||
number: 1, |
||||
gas_used: 99523, |
||||
timestamp: time |
||||
}) |
||||
|
||||
to_address = insert(:address, hash: "0xsleepypuppy") |
||||
from_address = insert(:address, hash: "0xilovefrogs") |
||||
|
||||
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}"), |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|> with_block(block) |
||||
|
||||
insert(:receipt, status: 1, transaction: transaction) |
||||
|
||||
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 == %{ |
||||
block_number: 1, |
||||
age: "2 hours ago", |
||||
formatted_age: "2 hours ago (#{formatted_timestamp})", |
||||
formatted_timestamp: formatted_timestamp, |
||||
cumulative_gas_used: "99,523", |
||||
to_address_hash: "0xsleepypuppy", |
||||
from_address_hash: "0xilovefrogs", |
||||
confirmations: 23, |
||||
status: :success, |
||||
formatted_status: "Success", |
||||
first_seen: "48 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, %{ |
||||
number: 1, |
||||
gas_used: 99523, |
||||
timestamp: time |
||||
}) |
||||
|
||||
to_address = insert(:address, hash: "0xsleepypuppy") |
||||
from_address = insert(:address, hash: "0xilovefrogs") |
||||
|
||||
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}"), |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|> with_block(block) |
||||
|
||||
insert(:receipt, status: 0, gas_used: 100, transaction: transaction) |
||||
|
||||
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 == %{ |
||||
block_number: 1, |
||||
age: "2 hours ago", |
||||
formatted_age: "2 hours ago (#{formatted_timestamp})", |
||||
formatted_timestamp: formatted_timestamp, |
||||
cumulative_gas_used: "99,523", |
||||
to_address_hash: "0xsleepypuppy", |
||||
from_address_hash: "0xilovefrogs", |
||||
confirmations: 23, |
||||
status: :failed, |
||||
formatted_status: "Failed", |
||||
first_seen: "48 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, %{ |
||||
number: 1, |
||||
gas_used: 99523, |
||||
timestamp: time |
||||
}) |
||||
|
||||
to_address = insert(:address, hash: "0xsleepypuppy") |
||||
from_address = insert(:address, hash: "0xilovefrogs") |
||||
|
||||
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}"), |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|> with_block(block) |
||||
|
||||
insert(:receipt, status: 0, gas_used: 555, transaction: transaction) |
||||
|
||||
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 == %{ |
||||
block_number: 1, |
||||
age: "2 hours ago", |
||||
formatted_age: "2 hours ago (#{formatted_timestamp})", |
||||
formatted_timestamp: formatted_timestamp, |
||||
cumulative_gas_used: "99,523", |
||||
to_address_hash: "0xsleepypuppy", |
||||
from_address_hash: "0xilovefrogs", |
||||
confirmations: 23, |
||||
status: :out_of_gas, |
||||
formatted_status: "Out of Gas", |
||||
first_seen: "48 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, %{ |
||||
number: 1, |
||||
gas_used: 99523, |
||||
timestamp: time |
||||
}) |
||||
|
||||
to_address = insert(:address, hash: "0xsleepypuppy") |
||||
from_address = insert(:address, hash: "0xilovefrogs") |
||||
|
||||
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}"), |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|> with_block(block) |
||||
|> 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 == %{ |
||||
block_number: 1, |
||||
age: "2 hours ago", |
||||
formatted_age: "2 hours ago (#{formatted_timestamp})", |
||||
formatted_timestamp: formatted_timestamp, |
||||
cumulative_gas_used: "99,523", |
||||
to_address_hash: "0xsleepypuppy", |
||||
from_address_hash: "0xilovefrogs", |
||||
confirmations: 23, |
||||
status: :pending, |
||||
formatted_status: "Pending", |
||||
first_seen: "48 years ago", |
||||
last_seen: "38 years ago" |
||||
} |
||||
) |
||||
end |
||||
|
||||
test "returns a pending transaction when there is no block" do |
||||
to_address = insert(:address, hash: "0xchadmuska") |
||||
from_address = insert(:address, hash: "0xtonyhawk") |
||||
|
||||
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}"), |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id |
||||
) |
||||
|> Repo.preload([:to_address, :from_address]) |
||||
|
||||
form = TransactionForm.build(transaction) |
||||
|
||||
assert( |
||||
form == %{ |
||||
block_number: "", |
||||
age: "Pending", |
||||
formatted_age: "Pending", |
||||
formatted_timestamp: "Pending", |
||||
cumulative_gas_used: "Pending", |
||||
to_address_hash: "0xchadmuska", |
||||
from_address_hash: "0xtonyhawk", |
||||
confirmations: 0, |
||||
status: :pending, |
||||
formatted_status: "Pending", |
||||
first_seen: "48 years ago", |
||||
last_seen: "38 years ago" |
||||
} |
||||
) |
||||
end |
||||
|
||||
test "works when there are no addresses" do |
||||
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}"), |
||||
to_address_id: nil, |
||||
from_address_id: nil |
||||
) |
||||
|> Repo.preload([:block, :to_address, :from_address]) |
||||
|
||||
form = TransactionForm.build(transaction) |
||||
|
||||
assert( |
||||
form == %{ |
||||
block_number: "", |
||||
age: "Pending", |
||||
formatted_age: "Pending", |
||||
formatted_timestamp: "Pending", |
||||
cumulative_gas_used: "Pending", |
||||
to_address_hash: nil, |
||||
from_address_hash: nil, |
||||
confirmations: 0, |
||||
status: :pending, |
||||
formatted_status: "Pending", |
||||
first_seen: "48 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, %{ |
||||
number: 1, |
||||
gas_used: 99523, |
||||
timestamp: time |
||||
}) |
||||
|
||||
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 |
||||
) |
||||
|> with_block(block) |
||||
|
||||
insert(:receipt, status: 0, gas_used: 555, transaction: transaction) |
||||
|
||||
form = |
||||
transaction |
||||
|> Repo.preload([:block, :to_address, :from_address, :receipt]) |
||||
|> TransactionForm.build_and_merge() |
||||
|
||||
assert form.hash == "0xkittenpower" |
||||
assert form.block_number == 1 |
||||
assert form.formatted_status == "Out of Gas" |
||||
end |
||||
end |
||||
end |
@ -1,19 +0,0 @@ |
||||
defmodule ExplorerWeb.WeiConverterTest do |
||||
use ExUnit.Case |
||||
|
||||
alias ExplorerWeb.WeiConverter |
||||
|
||||
test "it converts wei to ether correctly" do |
||||
wei = Decimal.new(239_047_000_000_000) |
||||
expected_value = Decimal.new(0.000239047) |
||||
|
||||
assert WeiConverter.to_ether(wei) == expected_value |
||||
end |
||||
|
||||
test "it converts wei to Gwei correctly" do |
||||
wei = Decimal.new(239_047_123_000_000) |
||||
expected_value = Decimal.new(239_047.123) |
||||
|
||||
assert WeiConverter.to_gwei(wei) == expected_value |
||||
end |
||||
end |
@ -0,0 +1,57 @@ |
||||
defmodule ExplorerWeb.TransactionViewTest do |
||||
use ExplorerWeb.ConnCase, async: true |
||||
|
||||
alias Explorer.Chain.Transaction |
||||
alias Explorer.Repo |
||||
alias ExplorerWeb.TransactionView |
||||
|
||||
describe "formatted_status/1" do |
||||
test "without receipt" do |
||||
transaction = |
||||
:transaction |
||||
|> insert() |
||||
|> Repo.preload(:receipt) |
||||
|
||||
assert TransactionView.formatted_status(transaction) == "Pending" |
||||
end |
||||
|
||||
test "with receipt with status 0 with gas_used < gas" do |
||||
gas = 2 |
||||
%Transaction{id: id} = insert(:transaction, gas: gas) |
||||
insert(:receipt, gas_used: gas - 1, status: 0, transaction_id: id) |
||||
|
||||
transaction = |
||||
Transaction |
||||
|> Repo.get!(id) |
||||
|> Repo.preload(:receipt) |
||||
|
||||
assert TransactionView.formatted_status(transaction) == "Failed" |
||||
end |
||||
|
||||
test "with receipt with status 0 with gas <= gas_used" do |
||||
gas = 2 |
||||
%Transaction{id: id} = insert(:transaction, gas: gas) |
||||
insert(:receipt, gas_used: gas, status: 0, transaction_id: id) |
||||
|
||||
transaction = |
||||
Transaction |
||||
|> Repo.get!(id) |
||||
|> Repo.preload(:receipt) |
||||
|
||||
assert TransactionView.formatted_status(transaction) == "Out of Gas" |
||||
end |
||||
|
||||
test "with receipt with status 1" do |
||||
gas = 2 |
||||
%Transaction{id: id} = insert(:transaction, gas: gas) |
||||
insert(:receipt, gas_used: gas - 1, status: 1, transaction_id: id) |
||||
|
||||
transaction = |
||||
Transaction |
||||
|> Repo.get!(id) |
||||
|> Repo.preload(:receipt) |
||||
|
||||
assert TransactionView.formatted_status(transaction) == "Success" |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue