Merge branch 'master' into ab-async-contract-verification

pull/2264/head
Ayrat Badykov 5 years ago committed by GitHub
commit 66b6eff339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      CHANGELOG.md
  2. 6
      apps/block_scout_web/assets/css/_typography.scss
  3. 11
      apps/block_scout_web/assets/css/components/_network-selector.scss
  4. 5
      apps/block_scout_web/assets/css/components/_tile.scss
  5. 60
      apps/block_scout_web/assets/css/components/_token-balance-dropdown.scss
  6. 7
      apps/block_scout_web/assets/css/components/_transaction.scss
  7. 9
      apps/block_scout_web/assets/css/theme/_neutral_variables.scss
  8. 9
      apps/block_scout_web/assets/css/theme/_poa_variables.scss
  9. 2
      apps/block_scout_web/assets/js/lib/currency.js
  10. 2
      apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
  11. 1
      apps/block_scout_web/lib/block_scout_web/controllers/page_not_found_controller.ex
  12. 23
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
  13. 3
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex
  14. 10
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex
  15. 6
      apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex
  16. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction/_token_transfer.html.eex
  17. 2
      apps/block_scout_web/priv/gettext/default.pot
  18. 11
      apps/block_scout_web/test/block_scout_web/controllers/page_not_found_controller_test.exs
  19. 19
      apps/explorer/lib/explorer/chain.ex
  20. 3
      apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex
  21. 61
      apps/explorer/test/explorer/chain/import/runner/internal_transactions_test.exs
  22. 17
      apps/explorer/test/explorer/chain_test.exs
  23. 16
      apps/indexer/lib/indexer/temporary/blocks_transactions_mismatch.ex

@ -13,6 +13,10 @@
- [#2266](https://github.com/poanetwork/blockscout/pull/2266) - allow excluding uncles from average block time calculation
### Fixes
- [#2284](https://github.com/poanetwork/blockscout/pull/2284) - add 404 status for not existing pages
- [#2244](https://github.com/poanetwork/blockscout/pull/2244) - fix internal transactions failing to be indexed because of constraint
- [#2281](https://github.com/poanetwork/blockscout/pull/2281) - typo issues, dropdown issues
- [#2278](https://github.com/poanetwork/blockscout/pull/2278) - increase threshold for scientific notation
- [#2275](https://github.com/poanetwork/blockscout/pull/2275) - Description for networks selector
- [#2263](https://github.com/poanetwork/blockscout/pull/2263) - added an ability to close network selector on outside click
- [#2257](https://github.com/poanetwork/blockscout/pull/2257) - 'download csv' button added to different tabs
@ -60,8 +64,11 @@
- [#2167](https://github.com/poanetwork/blockscout/pull/2167) - feat: document eth rpc api mimicking endpoints
- [#2225](https://github.com/poanetwork/blockscout/pull/2225) - fix metadata decoding in Solidity 0.5.9 smart contract verification
- [#2204](https://github.com/poanetwork/blockscout/pull/2204) - fix large contract verification
- [#2258](https://github.com/poanetwork/blockscout/pull/2258) - reduce BlocksTransactionsMismatch memory footprint
- [#2247](https://github.com/poanetwork/blockscout/pull/2247) - hide logs search if there are no logs
- [#2248](https://github.com/poanetwork/blockscout/pull/2248) - sort block after query execution for average block time
- [#2249](https://github.com/poanetwork/blockscout/pull/2249) - More transaction controllers improvements
- [#2267](https://github.com/poanetwork/blockscout/pull/2267) - Modify implementation of `where_transaction_has_multiple_internal_transactions`
- [#2270](https://github.com/poanetwork/blockscout/pull/2270) - Remove duplicate params in `Indexer.Fetcher.TokenBalance`
- [#2268](https://github.com/poanetwork/blockscout/pull/2268) - remove not existing assigns in html code
- [#2276](https://github.com/poanetwork/blockscout/pull/2276) - remove port in docs

@ -73,8 +73,12 @@ textarea.form-control {
}
.contract-address {
border-bottom: 1px dashed currentColor;
display: inline-block;
text-decoration: underline;
text-decoration-style: dashed;
&:hover {
text-decoration-style: none;
}
}
.text {

@ -1,6 +1,7 @@
$network-selector-overlay-background: $modal-overlay-color !default;
$network-selector-close-color: $primary !default;
$network-selector-horizontal-padding: 28px;
$network-selector-horizontal-mobile-padding: 14px;
$btn-network-selector-load-more-background: #fff !default;
$btn-network-selector-load-more-color: $primary !default;
$network-selector-search-input-color: #a3a9b5 !default;
@ -143,7 +144,10 @@ $network-selector-item-icon-dimensions: 30px !default;
border-bottom: 1px solid $base-border-color;
display: flex;
flex-shrink: 0;
margin: 0 $network-selector-horizontal-padding;
margin: 0 $network-selector-horizontal-mobile-padding;
@media (min-width: 375px) {
margin: 0 $network-selector-horizontal-padding;
}
}
.network-selector-tab {
@ -277,7 +281,10 @@ $network-selector-item-icon-dimensions: 30px !default;
flex-shrink: 1;
min-height: 100px;
overflow: auto;
padding: 0 $network-selector-horizontal-padding;
padding: 0 $network-selector-horizontal-mobile-padding;
@media (min-width: 375px) {
padding: 0 $network-selector-horizontal-padding;
}
}
.network-selector-load-more-container {

@ -174,6 +174,11 @@ $tile-body-a-color: #5959d8 !default;
.tile-body {
a {
color: $tile-body-a-color;
&:hover {
span {
text-decoration: underline;
}
}
}
}

@ -1,21 +1,61 @@
.token-balance-dropdown {
min-width: 14.375rem;
min-width: 10rem;
margin-top: 1rem;
background-color: $gray-100;
box-shadow: 0 2px 3px 2px $gray-200;
border: none;
background-color: #fff;
&.dropdown-menu {
border-radius: 4px !important;
box-shadow: 0 0.5rem 1rem rgba(202, 199, 226, .3) !important;
border: 1px solid #e2e5ec !important;
}
.dropdown-items {
overflow-y: auto;
max-height: 18.5rem;
.dropdown-item:hover {
color: $white;
.dropdown-item {
&:hover {
color: $secondary;
}
.row:nth-child(2) {
p {
font-size: 12px;
opacity: .65;
}
}
}
}
&:after,
&:before {
.dropdown-header {
padding: 1.1rem 20px .9rem 20px;
font-size: 14px;
font-weight: 400;
}
.dropdown-search-field {
height: 50px;
border: 1px solid #f5f6fa;
background-color: #f5f6fa;
outline: none !important;
font-size: 14px;
color: #828ba0;
font-weight: 300;
padding-left: 52px;
&::placeholder {
color: rgba(#828ba0, .5);
}
}
.dropdown-search-icon {
left: 20px;
top: 50%;
margin-top: -8.5px;
path {
fill: #828ba0;
}
}
&:after {
bottom: 100%;
right: 14%;
border: solid transparent;
@ -26,8 +66,6 @@
}
&:before {
border-bottom-color: $gray-100;
border-width: 0.5rem;
margin-left: -0.5rem;
display: none;
}
}

@ -27,19 +27,20 @@
margin-top: 30px;
}
.download-all-transactions-link {
display: inline-flex;
align-items: center;
text-decoration: none;
svg {
position: relative;
margin-left: 2px;
top: -3px;
left: 3px;
path {
fill: $primary;
}
}
&:hover {
span {
text-decoration: underline;
}
text-decoration: underline;
}
}
}

@ -64,4 +64,11 @@ $card-tab-active: $primary;
// Badges
$badge-neutral-color: $primary;
$badge-neutral-background-color: rgba($primary, .1);
$api-text-monospace-color: $primary;
$api-text-monospace-color: $primary;
// Tokens dropdown
.token-balance-dropdown[aria-labelledby="dropdown-tokens"] {
.dropdown-items .dropdown-item:hover {
color: $primary !important;
}
}

@ -64,4 +64,11 @@ $card-tab-active: $primary;
// Badges
$badge-neutral-color: $primary;
$badge-neutral-background-color: rgba($primary, .1);
$api-text-monospace-color: $primary;
$api-text-monospace-color: $primary;
// Tokens dropdown
.token-balance-dropdown[aria-labelledby="dropdown-tokens"] {
.dropdown-items .dropdown-item:hover {
color: $primary !important;
}
}

@ -18,7 +18,7 @@ function formatCurrencyValue (value, symbol) {
if (value < 0.000001) return `${window.localized['Less than']} ${symbol}0.000001`
if (value < 1) return `${symbol}${numeral(value).format('0.000000')}`
if (value < 100000) return `${symbol}${numeral(value).format('0,0.00')}`
if (value > 1000000000) return `${symbol}${numeral(value).format('0.000e+0')}`
if (value > 1000000000000) return `${symbol}${numeral(value).format('0.000e+0')}`
return `${symbol}${numeral(value).format('0,0')}`
}

@ -17,7 +17,7 @@ defmodule BlockScoutWeb.BlockTransactionController do
Keyword.merge(
[
necessity_by_association: %{
:block => :required,
:block => :optional,
[created_contract_address: :names] => :optional,
[from_address: :names] => :required,
[to_address: :names] => :optional

@ -3,6 +3,7 @@ defmodule BlockScoutWeb.PageNotFoundController do
def index(conn, _params) do
conn
|> put_status(:not_found)
|> render("index.html")
end
end

@ -61,21 +61,16 @@ defmodule BlockScoutWeb.TransactionController do
end
def show(conn, %{"id" => id}) do
case Chain.string_to_transaction_hash(id) do
{:ok, transaction_hash} -> show_transaction(conn, id, Chain.hash_to_transaction(transaction_hash))
:error -> conn |> put_status(422) |> render("invalid.html", transaction_hash: id)
end
end
defp show_transaction(conn, id, {:error, :not_found}) do
conn |> put_status(404) |> render("not_found.html", transaction_hash: id)
end
defp show_transaction(conn, id, {:ok, %Chain.Transaction{} = transaction}) do
if Chain.transaction_has_token_transfers?(transaction.hash) do
redirect(conn, to: transaction_token_transfer_path(conn, :index, id))
with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(id),
{:ok, %Chain.Transaction{} = transaction} <- Chain.hash_to_transaction(transaction_hash) do
if Chain.transaction_has_token_transfers?(transaction.hash) do
redirect(conn, to: transaction_token_transfer_path(conn, :index, id))
else
redirect(conn, to: transaction_internal_transaction_path(conn, :index, id))
end
else
redirect(conn, to: transaction_internal_transaction_path(conn, :index, id))
:error -> conn |> put_status(422) |> render("invalid.html", transaction_hash: id)
{:error, :not_found} -> conn |> put_status(404) |> render("not_found.html", transaction_hash: id)
end
end
end

@ -17,7 +17,8 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional
[to_address: :names] => :optional,
[transaction: :block] => :optional
}
],
paging_options(params)

@ -19,15 +19,7 @@ defmodule BlockScoutWeb.TransactionRawTraceController do
:token_transfers => :optional
}
) do
options = [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional
}
]
internal_transactions = Chain.transaction_to_internal_transactions(transaction, options)
internal_transactions = Chain.transaction_to_internal_transactions(transaction)
render(
conn,

@ -18,8 +18,10 @@
<div class="dropdown-menu dropdown-menu-right token-balance-dropdown p-0" aria-labelledby="dropdown-tokens">
<div data-dropdown-items class="dropdown-items">
<div class="m-3 position-relative">
<i class="fas fa-search position-absolute dropdown-search-icon"></i>
<div class="position-relative">
<svg class="position-absolute dropdown-search-icon" viewBox="0 0 16 17" xmlns="http://www.w3.org/2000/svg" width="16" height="17" class="dropdown-search-icon position-absolute">
<path fill="#7DD79F" fill-rule="evenodd" d="M15.713 15.727a.982.982 0 0 1-1.388 0l-2.289-2.29C10.773 14.403 9.213 15 7.5 15A7.5 7.5 0 1 1 15 7.5c0 1.719-.602 3.284-1.575 4.55l2.288 2.288a.983.983 0 0 1 0 1.389zM7.5 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 1 0 0-11z"></path>
</svg>
<%= text_input(
:token_search,
:name,

@ -1,5 +1,5 @@
<div class="text-nowrap row mt-3 mt-sm-0" data-test="token_transfer">
<span class="col-12 col-md-5">
<span class="col-xs-12 col-lg-5">
<%= if from_or_to_address?(@token_transfer, @address) do %>
<%= if @token_transfer.from_address_hash == @address.hash do %>
<span data-test="transaction_type" class="text-danger">
@ -19,7 +19,7 @@
<%= @token_transfer |> BlockScoutWeb.AddressView.address_partial_selector(:to, @address, true) |> BlockScoutWeb.RenderHelpers.render_partial() %>
</span>
</span>
<span class="col-12 col-md-7 ml-3 ml-sm-0">
<span class="col-xs-12 col-lg-4 ml-3 ml-sm-0">
<%= token_transfer_amount(@token_transfer) %>
<%= link(token_symbol(@token_transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, @token_transfer.token.contract_address_hash)) %>
</span>

@ -674,7 +674,7 @@ msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:28
#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:30
msgid "Search tokens"
msgstr ""

@ -0,0 +1,11 @@
defmodule BlockScoutWeb.PageNotFoundControllerTest do
use BlockScoutWeb.ConnCase
describe "GET index/2" do
test "returns 404 status", %{conn: conn} do
conn = get(conn, "/wrong", %{})
assert html_response(conn, 404)
end
end
end

@ -1052,7 +1052,7 @@ defmodule Explorer.Chain do
when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
fetch_transactions()
Transaction
|> where(hash: ^hash)
|> join_associations(necessity_by_association)
|> Repo.one()
@ -1953,7 +1953,6 @@ defmodule Explorer.Chain do
|> Keyword.get(:paging_options, @default_paging_options)
|> fetch_transactions()
|> where([transaction], not is_nil(transaction.block_number) and not is_nil(transaction.index))
|> order_by([transaction], desc: transaction.block_number, desc: transaction.index)
|> join_associations(necessity_by_association)
|> preload([{:token_transfers, [:token, :from_address, :to_address]}])
|> Repo.all()
@ -2146,7 +2145,7 @@ defmodule Explorer.Chain do
|> page_internal_transaction(paging_options)
|> limit(^paging_options.page_size)
|> order_by([internal_transaction], asc: internal_transaction.index)
|> preload(transaction: :block)
|> preload(:transaction)
|> Repo.all()
end
@ -2580,14 +2579,14 @@ defmodule Explorer.Chain do
internal_transaction.type != ^:call or
fragment(
"""
(SELECT COUNT(sibling.*)
EXISTS (SELECT sibling.*
FROM internal_transactions AS sibling
WHERE sibling.transaction_hash = ?
LIMIT 2
WHERE sibling.transaction_hash = ? AND sibling.index != ?
)
""",
transaction.hash
) > 1
transaction.hash,
internal_transaction.index
)
)
end
@ -2707,9 +2706,9 @@ defmodule Explorer.Chain do
@spec transaction_has_token_transfers?(Hash.t()) :: boolean()
def transaction_has_token_transfers?(transaction_hash) do
query = from(tt in TokenTransfer, where: tt.transaction_hash == ^transaction_hash, limit: 1, select: 1)
query = from(tt in TokenTransfer, where: tt.transaction_hash == ^transaction_hash)
Repo.one(query) != nil
Repo.exists?(query)
end
@spec address_tokens_with_balance(Hash.Address.t(), [any()]) :: []

@ -171,8 +171,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
),
status:
fragment(
"COALESCE(?, CASE WHEN (SELECT it.error FROM internal_transactions AS it WHERE it.transaction_hash = ? ORDER BY it.index ASC LIMIT 1) IS NULL THEN ? ELSE ? END)",
t.status,
"CASE WHEN (SELECT it.error FROM internal_transactions AS it WHERE it.transaction_hash = ? ORDER BY it.index ASC LIMIT 1) IS NULL THEN ? ELSE ? END",
t.hash,
type(^:ok, t.status),
type(^:error, t.status)

@ -0,0 +1,61 @@
defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
use Explorer.DataCase
alias Ecto.Multi
alias Explorer.Chain.{Data, Wei, Transaction}
alias Explorer.Chain.Import.Runner.InternalTransactions
describe "run/1" do
test "transaction's status becomes :error when its internal_transaction has an error" do
transaction = insert(:transaction) |> with_block(status: :ok)
assert :ok == transaction.status
index = 0
error = "Reverted"
internal_transaction_changes = make_internal_transaction_changes(transaction.hash, index, error)
assert {:ok, _} = run_internal_transactions([internal_transaction_changes])
assert :error == Repo.get(Transaction, transaction.hash).status
end
end
defp run_internal_transactions(changes_list) when is_list(changes_list) do
Multi.new()
|> InternalTransactions.run(changes_list, %{
timeout: :infinity,
timestamps: %{inserted_at: DateTime.utc_now(), updated_at: DateTime.utc_now()}
})
|> Repo.transaction()
end
defp make_internal_transaction_changes(transaction_hash, index, error) do
%{
from_address_hash: insert(:address).hash,
to_address_hash: insert(:address).hash,
call_type: :call,
gas: 22234,
gas_used:
if is_nil(error) do
18920
else
nil
end,
input: %Data{bytes: <<1>>},
output:
if is_nil(error) do
%Data{bytes: <<2>>}
else
nil
end,
index: index,
trace_address: [],
transaction_hash: transaction_hash,
type: :call,
value: Wei.from(Decimal.new(1), :wei),
error: error
}
end
end

@ -2110,11 +2110,14 @@ defmodule Explorer.ChainTest do
])
)
assert internal_transaction.transaction.block.number == block.number
assert internal_transaction.transaction.block_number == block.number
end
test "with transaction with internal transactions loads associations with in necessity_by_association" do
transaction = insert(:transaction)
transaction =
:transaction
|> insert()
|> with_block()
insert(:internal_transaction_create,
transaction: transaction,
@ -2127,7 +2130,7 @@ defmodule Explorer.ChainTest do
%InternalTransaction{
from_address: %Ecto.Association.NotLoaded{},
to_address: %Ecto.Association.NotLoaded{},
transaction: %Transaction{}
transaction: %Transaction{block: %Ecto.Association.NotLoaded{}}
}
] = Chain.transaction_to_internal_transactions(transaction)
@ -2135,15 +2138,15 @@ defmodule Explorer.ChainTest do
%InternalTransaction{
from_address: %Address{},
to_address: nil,
transaction: %Transaction{}
transaction: %Transaction{block: %Block{}}
}
] =
Chain.transaction_to_internal_transactions(
transaction,
necessity_by_association: %{
from_address: :optional,
to_address: :optional,
transaction: :optional
:from_address => :optional,
:to_address => :optional,
[transaction: :block] => :optional
}
)
end

@ -54,7 +54,7 @@ defmodule Indexer.Temporary.BlocksTransactionsMismatch do
left_join: transactions in assoc(block, :transactions),
where: block.consensus and block.refetch_needed,
group_by: block.hash,
select: {block, count(transactions.hash)}
select: {block.hash, count(transactions.hash)}
)
{:ok, final} = Repo.stream_reduce(query, initial, &reducer.(&1, &2))
@ -64,7 +64,7 @@ defmodule Indexer.Temporary.BlocksTransactionsMismatch do
@impl BufferedTask
def run(blocks_data, json_rpc_named_arguments) do
hashes = Enum.map(blocks_data, fn {block, _trans_num} -> block.hash end)
hashes = Enum.map(blocks_data, fn {hash, _trans_num} -> hash end)
Logger.debug("fetching")
@ -95,17 +95,17 @@ defmodule Indexer.Temporary.BlocksTransactionsMismatch do
|> Map.merge(blocks_with_transactions_map)
{found_blocks_data, missing_blocks_data} =
Enum.split_with(blocks_data, fn {block, _trans_num} ->
Map.has_key?(found_blocks_map, to_string(block.hash))
Enum.split_with(blocks_data, fn {hash, _trans_num} ->
Map.has_key?(found_blocks_map, to_string(hash))
end)
{matching_blocks_data, unmatching_blocks_data} =
Enum.split_with(found_blocks_data, fn {block, trans_num} ->
found_blocks_map[to_string(block.hash)] == trans_num
Enum.split_with(found_blocks_data, fn {hash, trans_num} ->
found_blocks_map[to_string(hash)] == trans_num
end)
unless Enum.empty?(matching_blocks_data) do
hashes = Enum.map(matching_blocks_data, fn {block, _trans_num} -> block.hash end)
hashes = Enum.map(matching_blocks_data, fn {hash, _trans_num} -> hash end)
Block
|> where([block], block.hash in ^hashes)
@ -113,7 +113,7 @@ defmodule Indexer.Temporary.BlocksTransactionsMismatch do
end
unless Enum.empty?(unmatching_blocks_data) do
hashes = Enum.map(unmatching_blocks_data, fn {block, _trans_num} -> block.hash end)
hashes = Enum.map(unmatching_blocks_data, fn {hash, _trans_num} -> hash end)
Block
|> where([block], block.hash in ^hashes)

Loading…
Cancel
Save