Merge branch 'master' into ab-erc-721-coin-instance-page

pull/2642/head
Victor Baranov 5 years ago committed by GitHub
commit d8071728b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      CHANGELOG.md
  2. 4
      apps/block_scout_web/assets/css/_layout.scss
  3. 4
      apps/block_scout_web/assets/css/components/_address-overview.scss
  4. 64
      apps/block_scout_web/assets/css/theme/_dark-theme.scss
  5. 3
      apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
  6. 5
      apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex
  7. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
  8. 2
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  9. 2
      apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
  10. 2
      apps/block_scout_web/mix.exs
  11. 5
      apps/block_scout_web/priv/gettext/default.pot
  12. 5
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  13. 2
      apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs
  14. 2
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  15. 2
      apps/block_scout_web/test/support/conn_case.ex
  16. 2
      apps/block_scout_web/test/support/feature_case.ex
  17. 8
      apps/explorer/config/config.exs
  18. 8
      apps/explorer/lib/explorer/application.ex
  19. 67
      apps/explorer/lib/explorer/chain.ex
  20. 42
      apps/explorer/lib/explorer/chain/cache/pending_transactions.ex
  21. 48
      apps/explorer/lib/explorer/chain/cache/uncles.ex
  22. 83
      apps/explorer/lib/explorer/chain/import/runner/blocks.ex
  23. 109
      apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex
  24. 6
      apps/explorer/lib/explorer/chain/import/runner/internal_transactions_indexed_at_blocks.ex
  25. 15
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  26. 17
      apps/explorer/test/explorer/chain/cache/pending_transactions_test.exs
  27. 28
      apps/explorer/test/explorer/chain/cache/uncles_test.exs
  28. 74
      apps/explorer/test/explorer/chain/import/runner/internal_transactions_test.exs
  29. 28
      apps/explorer/test/explorer/smart_contract/verifier_test.exs
  30. 2
      apps/explorer/test/support/data_case.ex
  31. 15
      apps/indexer/lib/indexer/block/fetcher.ex
  32. 3
      apps/indexer/lib/indexer/fetcher/pending_transaction.ex
  33. 9
      apps/indexer/lib/indexer/fetcher/uncle_block.ex
  34. 2
      apps/indexer/lib/indexer/temporary/uncles_without_index.ex
  35. 2
      mix.lock

@ -1,7 +1,9 @@
## Current ## Current
### Features ### Features
- [#2642](https://github.com/poanetwork/blockscout/pull/2642) - add ERC721 coin instance page - [#2733](https://github.com/poanetwork/blockscout/pull/2733) - Add cache for first page of uncles
- [#2735](https://github.com/poanetwork/blockscout/pull/2735) - Add pending transactions cache
- [#2726](https://github.com/poanetwork/blockscout/pull/2726) - Remove internal_transaction block_number setting from blocks runner
- [#2717](https://github.com/poanetwork/blockscout/pull/2717) - Improve speed of nonconsensus data removal - [#2717](https://github.com/poanetwork/blockscout/pull/2717) - Improve speed of nonconsensus data removal
- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions - [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions
- [#2678](https://github.com/poanetwork/blockscout/pull/2678) - fixed dashboard banner height bug - [#2678](https://github.com/poanetwork/blockscout/pull/2678) - fixed dashboard banner height bug
@ -10,9 +12,17 @@
- [#2666](https://github.com/poanetwork/blockscout/pull/2666) - fetch token counters in parallel - [#2666](https://github.com/poanetwork/blockscout/pull/2666) - fetch token counters in parallel
- [#2665](https://github.com/poanetwork/blockscout/pull/2665) - new menu layout for mobile devices - [#2665](https://github.com/poanetwork/blockscout/pull/2665) - new menu layout for mobile devices
- [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel - [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel
- [#2642](https://github.com/poanetwork/blockscout/pull/2642) - add ERC721 coin instance page
### Fixes ### Fixes
- [#2750](https://github.com/poanetwork/blockscout/pull/2750) - fixed contract buttons color for NFT token instance on each theme - [#2750](https://github.com/poanetwork/blockscout/pull/2750) - fixed contract buttons color for NFT token instance on each theme
- [#2746](https://github.com/poanetwork/blockscout/pull/2746) - fixed wrong alignment in logs decoded view
- [#2745](https://github.com/poanetwork/blockscout/pull/2745) - optimize addresses page
- [#2742](https://github.com/poanetwork/blockscout/pull/2742) -
fixed menu hovers in dark mode desktop view
- [#2737](https://github.com/poanetwork/blockscout/pull/2737) - switched hardcoded subnetwork value to elixir expression for mobile menu
- [#2736](https://github.com/poanetwork/blockscout/pull/2736) - do not update cache if no blocks were inserted
- [#2731](https://github.com/poanetwork/blockscout/pull/2731) - fix library verification
- [#2718](https://github.com/poanetwork/blockscout/pull/2718) - Include all addresses taking part in transactions in wallets' addresses counter - [#2718](https://github.com/poanetwork/blockscout/pull/2718) - Include all addresses taking part in transactions in wallets' addresses counter
- [#2709](https://github.com/poanetwork/blockscout/pull/2709) - Fix stuck label and value for uncle block height - [#2709](https://github.com/poanetwork/blockscout/pull/2709) - Fix stuck label and value for uncle block height
- [#2707](https://github.com/poanetwork/blockscout/pull/2707) - fix for dashboard banner chart legend items - [#2707](https://github.com/poanetwork/blockscout/pull/2707) - fix for dashboard banner chart legend items
@ -28,10 +38,12 @@
- [#2671](https://github.com/poanetwork/blockscout/pull/2671) - fixed buttons color at smart contract section - [#2671](https://github.com/poanetwork/blockscout/pull/2671) - fixed buttons color at smart contract section
- [#2660](https://github.com/poanetwork/blockscout/pull/2660) - set correct last value for coin balances chart data - [#2660](https://github.com/poanetwork/blockscout/pull/2660) - set correct last value for coin balances chart data
- [#2619](https://github.com/poanetwork/blockscout/pull/2619) - Enforce DB transaction's order to prevent deadlocks - [#2619](https://github.com/poanetwork/blockscout/pull/2619) - Enforce DB transaction's order to prevent deadlocks
- [#2738](https://github.com/poanetwork/blockscout/pull/2738) - do not fail block `internal_transactions_indexed_at` field update
### Chore ### Chore
- [#2724](https://github.com/poanetwork/blockscout/pull/2724) - fix ci by commenting a line in hackney library - [#2724](https://github.com/poanetwork/blockscout/pull/2724) - fix ci by commenting a line in hackney library
- [#2708](https://github.com/poanetwork/blockscout/pull/2708) - add log index to logs view - [#2708](https://github.com/poanetwork/blockscout/pull/2708) - add log index to logs view
- [#2723](https://github.com/poanetwork/blockscout/pull/2723) - get rid of ex_json_schema warnings
## 2.0.4-beta ## 2.0.4-beta

@ -8,3 +8,7 @@
background-color: #fbfafc; background-color: #fbfafc;
} }
} }
.logs-hash {
line-height: 24px !important;
}

@ -79,4 +79,8 @@
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
}
.logs-decoded {
line-height: 25px!important;
} }

@ -792,35 +792,37 @@ $labels-dark: #8a8dba; // header nav, labels
.dark-theme-applied .dropdown-item.active, .dark-theme-applied .dropdown-item:hover, .dark-theme-applied .dropdown-item:focus { .dark-theme-applied .dropdown-item.active, .dark-theme-applied .dropdown-item:hover, .dark-theme-applied .dropdown-item:focus {
background-image: none; background-image: none;
width: 100%; width: 100%;
background-color: #35335d!important; background-color: #3f426c!important;
} }
.dark-theme-applied .dropdown-item:hover:before { @media (max-width: 991.98px) {
content: "|"; .dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover,
height: 50px; .dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link.activeLink,
width: 50%; .dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:focus {
opacity: 1; background-image: none;
background: none; width: 100%;
right: 17%; background-color: #35335d!important;
color: $dark-primary; color: white;
position: relative; border: none;
} }
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover, .dark-theme-applied .dropdown-item:hover:before {
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link.activeLink, content: "|";
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:focus { height: 50px;
background-image: none; width: 50%;
width: 100%; opacity: 1;
background-color: #35335d!important; background: none;
color: white; right: 17%;
border: none; color: $dark-primary;
} position: relative;
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover:before }
{ .dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover:before
content: "|"; {
height: 50px; content: "|";
width: 50%; height: 50px;
opacity: 1; width: 50%;
background: none; opacity: 1;
left: 24%; background: none;
top: 14%; left: 24%;
color: $dark-primary; top: 14%;
} color: $dark-primary;
}
}

@ -44,8 +44,7 @@ defmodule BlockScoutWeb.AddressController do
index: index, index: index,
exchange_rate: exchange_rate, exchange_rate: exchange_rate,
total_supply: total_supply, total_supply: total_supply,
tx_count: tx_count, tx_count: tx_count
validation_count: validation_count(address.hash)
) )
end) end)

@ -29,11 +29,6 @@
<span data-test="transaction_count"> <span data-test="transaction_count">
<%= @tx_count %> <%= @tx_count %>
</span> <%= gettext "Transactions sent" %> </span> <%= gettext "Transactions sent" %>
<% if validator?(@address) do %>
<span data-test="validation_count">
<%= @validation_count %>
</span> <%= gettext "Validations" %>
<% end %>
</span> </span>
</td> </td>
</tr> </tr>

@ -17,7 +17,7 @@
<dl class="row"> <dl class="row">
<dt class="col-md-2"> <%= gettext "Transaction" %> </dt> <dt class="col-md-2"> <%= gettext "Transaction" %> </dt>
<dd class="col-md-10"> <dd class="col-md-10">
<h3 class=""> <h3 class="logs-decoded">
<%= link( <%= link(
@log.transaction, @log.transaction,
to: transaction_path(@conn, :show, @log.transaction), to: transaction_path(@conn, :show, @log.transaction),

@ -16,7 +16,7 @@
<span class="nav-link-icon"> <span class="nav-link-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="6"> <svg xmlns="http://www.w3.org/2000/svg" width="6" height="6">
<circle cx="3" cy="3" r="3" fill="#80d6a1"></circle> <circle cx="3" cy="3" r="3" fill="#80d6a1"></circle>
</svg> </span>Sokol Testnet</a> </svg> </span><%= subnetwork_title() %></a>
<button class="new-button" id="dark-mode-changer"> <button class="new-button" id="dark-mode-changer">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="16"> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="16">
<path fill="#a3a9b5" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"></path> <path fill="#a3a9b5" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"></path>

@ -18,7 +18,7 @@
<dl class="row"> <dl class="row">
<dt class="col-lg-2"> <%= gettext "Address" %> </dt> <dt class="col-lg-2"> <%= gettext "Address" %> </dt>
<dd class="col-lg-10"> <dd class="col-lg-10">
<h3 class=""> <h3 class="logs-hash">
<%= link( <%= link(
@log.address, @log.address,
to: address_path(@conn, :show, @log.address), to: address_path(@conn, :show, @log.address),

@ -131,7 +131,7 @@ defmodule BlockScoutWeb.Mixfile do
# `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility
{:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"}, {:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"},
{:phoenix_form_awesomplete, "~> 0.1.4"}, {:phoenix_form_awesomplete, "~> 0.1.4"},
{:ex_json_schema, "~> 0.6.1"} {:ex_json_schema, "~> 0.6.2"}
] ]
end end

@ -1635,11 +1635,6 @@ msgstr ""
msgid "Validated Transactions" msgid "Validated Transactions"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tile.html.eex:35
msgid "Validations"
msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:30 #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:30
msgid "Validator Creation Date" msgid "Validator Creation Date"

@ -1635,11 +1635,6 @@ msgstr ""
msgid "Validated Transactions" msgid "Validated Transactions"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tile.html.eex:35
msgid "Validations"
msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:30 #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:30
msgid "Validator Creation Date" msgid "Validator Creation Date"

@ -5,6 +5,8 @@ defmodule BlockScoutWeb.BlockControllerTest do
setup do setup do
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
:ok :ok
end end

@ -11,6 +11,8 @@ defmodule BlockScoutWeb.ChainControllerTest do
setup do setup do
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
start_supervised!(AddressesCounter) start_supervised!(AddressesCounter)
AddressesCounter.consolidate() AddressesCounter.consolidate()

@ -44,6 +44,8 @@ defmodule BlockScoutWeb.ConnCase do
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
{:ok, conn: Phoenix.ConnTest.build_conn()} {:ok, conn: Phoenix.ConnTest.build_conn()}
end end

@ -31,6 +31,8 @@ defmodule BlockScoutWeb.FeatureCase do
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(Explorer.Repo, self()) metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(Explorer.Repo, self())
{:ok, session} = Wallaby.start_session(metadata: metadata) {:ok, session} = Wallaby.start_session(metadata: metadata)

@ -145,6 +145,14 @@ config :explorer, Explorer.Chain.Cache.Accounts,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
config :explorer, Explorer.Chain.Cache.PendingTransactions,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
config :explorer, Explorer.Chain.Cache.Uncles,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

@ -13,8 +13,10 @@ defmodule Explorer.Application do
BlockNumber, BlockNumber,
Blocks, Blocks,
NetVersion, NetVersion,
PendingTransactions,
TransactionCount, TransactionCount,
Transactions Transactions,
Uncles
} }
alias Explorer.Chain.Supply.RSK alias Explorer.Chain.Supply.RSK
@ -51,7 +53,9 @@ defmodule Explorer.Application do
con_cache_child_spec(MarketHistoryCache.cache_name()), con_cache_child_spec(MarketHistoryCache.cache_name()),
con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)), con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)),
Transactions, Transactions,
Accounts Accounts,
PendingTransactions,
Uncles
] ]
children = base_children ++ configurable_children() children = base_children ++ configurable_children()

@ -54,8 +54,10 @@ defmodule Explorer.Chain do
BlockCount, BlockCount,
BlockNumber, BlockNumber,
Blocks, Blocks,
PendingTransactions,
TransactionCount, TransactionCount,
Transactions Transactions,
Uncles
} }
alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner
@ -1344,20 +1346,43 @@ defmodule Explorer.Chain do
paging_options = Keyword.get(options, :paging_options) || @default_paging_options paging_options = Keyword.get(options, :paging_options) || @default_paging_options
block_type = Keyword.get(options, :block_type, "Block") block_type = Keyword.get(options, :block_type, "Block")
if block_type == "Block" && !paging_options.key do cond do
case Blocks.take_enough(paging_options.page_size) do block_type == "Block" && !paging_options.key ->
nil -> block_from_cache(block_type, paging_options, necessity_by_association)
elements = fetch_blocks(block_type, paging_options, necessity_by_association)
Blocks.update(elements) block_type == "Uncle" && !paging_options.key ->
uncles_from_cache(block_type, paging_options, necessity_by_association)
elements true ->
fetch_blocks(block_type, paging_options, necessity_by_association)
end
end
blocks -> defp block_from_cache(block_type, paging_options, necessity_by_association) do
blocks case Blocks.take_enough(paging_options.page_size) do
end nil ->
else elements = fetch_blocks(block_type, paging_options, necessity_by_association)
fetch_blocks(block_type, paging_options, necessity_by_association)
Blocks.update(elements)
elements
blocks ->
blocks
end
end
def uncles_from_cache(block_type, paging_options, necessity_by_association) do
case Uncles.take_enough(paging_options.page_size) do
nil ->
elements = fetch_blocks(block_type, paging_options, necessity_by_association)
Uncles.update(elements)
elements
blocks ->
blocks
end end
end end
@ -2216,6 +2241,24 @@ defmodule Explorer.Chain do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options) paging_options = Keyword.get(options, :paging_options, @default_paging_options)
if is_nil(paging_options.key) do
paging_options.page_size
|> PendingTransactions.take_enough()
|> case do
nil ->
pending_transactions = fetch_recent_pending_transactions(paging_options, necessity_by_association)
PendingTransactions.update(pending_transactions)
pending_transactions
pending_transactions ->
pending_transactions
end
else
fetch_recent_pending_transactions(paging_options, necessity_by_association)
end
end
defp fetch_recent_pending_transactions(paging_options, necessity_by_association) do
Transaction Transaction
|> page_pending_transaction(paging_options) |> page_pending_transaction(paging_options)
|> limit(^paging_options.page_size) |> limit(^paging_options.page_size)

@ -0,0 +1,42 @@
defmodule Explorer.Chain.Cache.PendingTransactions do
@moduledoc """
Caches the latest pending transactions
"""
alias Explorer.Chain.Transaction
use Explorer.Chain.OrderedCache,
name: :pending_transactions,
max_size: 51,
preloads: [
:block,
created_contract_address: :names,
from_address: :names,
to_address: :names,
token_transfers: :token,
token_transfers: :from_address,
token_transfers: :to_address
],
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
@type element :: Transaction.t()
@type id :: {non_neg_integer(), non_neg_integer()}
def element_to_id(%Transaction{inserted_at: inserted_at, hash: hash}) do
{inserted_at, hash}
end
def update_pending(transactions) when is_nil(transactions), do: :ok
def update_pending(transactions) do
transactions
|> Enum.filter(&pending?(&1))
|> update()
end
defp pending?(transaction) do
is_nil(transaction.block_hash) and (is_nil(transaction.error) or transaction.error != "dropped/replaced")
end
end

@ -0,0 +1,48 @@
defmodule Explorer.Chain.Cache.Uncles do
@moduledoc """
Caches the last known uncles
"""
alias Explorer.Chain.Block
alias Explorer.Repo
use Explorer.Chain.OrderedCache,
name: :uncles,
max_size: 60,
ids_list_key: "uncle_numbers",
preload: :transactions,
preload: [miner: :names],
preload: :rewards,
preload: :nephews,
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
import Ecto.Query
@type element :: Block.t()
@type id :: non_neg_integer()
def element_to_id(%Block{number: number}), do: number
def update_from_second_degree_relations(second_degree_relations) when is_nil(second_degree_relations), do: :ok
def update_from_second_degree_relations(second_degree_relations) do
uncle_hashes =
second_degree_relations
|> Enum.map(& &1.uncle_hash)
|> Enum.uniq()
query =
from(
block in Block,
where: block.consensus == false and block.hash in ^uncle_hashes,
inner_join: nephews in assoc(block, :nephews),
preload: [nephews: block]
)
query
|> Repo.all()
|> update()
end
end

@ -56,7 +56,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
# Note, needs to be executed after `lose_consensus` for lock acquisition # Note, needs to be executed after `lose_consensus` for lock acquisition
insert(repo, changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
|> Multi.run(:uncle_fetched_block_second_degree_relations, fn repo, %{blocks: blocks} when is_list(blocks) -> |> Multi.run(:uncle_fetched_block_second_degree_relations, fn repo, _ ->
update_block_second_degree_relations(repo, hashes, %{ update_block_second_degree_relations(repo, hashes, %{
timeout: timeout:
options[Runner.Block.SecondDegreeRelations.option_key()][:timeout] || options[Runner.Block.SecondDegreeRelations.option_key()][:timeout] ||
@ -86,15 +86,9 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
|> Multi.run(:remove_nonconsensus_logs, fn repo, %{derive_transaction_forks: transactions} -> |> Multi.run(:remove_nonconsensus_logs, fn repo, %{derive_transaction_forks: transactions} ->
remove_nonconsensus_logs(repo, transactions, insert_options) remove_nonconsensus_logs(repo, transactions, insert_options)
end) end)
|> Multi.run(:acquire_internal_transactions, fn repo, %{derive_transaction_forks: transactions} ->
acquire_internal_transactions(repo, hashes, transactions)
end)
|> Multi.run(:remove_nonconsensus_internal_transactions, fn repo, %{derive_transaction_forks: transactions} -> |> Multi.run(:remove_nonconsensus_internal_transactions, fn repo, %{derive_transaction_forks: transactions} ->
remove_nonconsensus_internal_transactions(repo, transactions, insert_options) remove_nonconsensus_internal_transactions(repo, transactions, insert_options)
end) end)
|> Multi.run(:internal_transaction_transaction_block_number, fn repo, _ ->
update_internal_transaction_block_number(repo, hashes)
end)
|> Multi.run(:acquire_contract_address_tokens, fn repo, _ -> |> Multi.run(:acquire_contract_address_tokens, fn repo, _ ->
acquire_contract_address_tokens(repo, consensus_block_numbers) acquire_contract_address_tokens(repo, consensus_block_numbers)
end) end)
@ -139,26 +133,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
Tokens.acquire_contract_address_tokens(repo, contract_address_hashes) Tokens.acquire_contract_address_tokens(repo, contract_address_hashes)
end end
defp acquire_internal_transactions(repo, hashes, forked_transaction_hashes) do
query =
from(internal_transaction in InternalTransaction,
join: transaction in Transaction,
on: internal_transaction.transaction_hash == transaction.hash,
where: transaction.block_hash in ^hashes,
or_where: transaction.hash in ^forked_transaction_hashes,
select: {internal_transaction.transaction_hash, internal_transaction.index},
# Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md)
order_by: [
internal_transaction.transaction_hash,
internal_transaction.index
],
# NOTE: find a better way to know the alias that ecto gives to token
lock: "FOR UPDATE OF i0"
)
{:ok, repo.all(query)}
end
defp fork_transactions(%{ defp fork_transactions(%{
repo: repo, repo: repo,
timeout: timeout, timeout: timeout,
@ -168,11 +142,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
query = query =
from( from(
transaction in where_forked(blocks_changes), transaction in where_forked(blocks_changes),
select: %{ select: transaction,
block_hash: transaction.block_hash,
index: transaction.index,
hash: transaction.hash
},
# Enforce Transaction ShareLocks order (see docs: sharelocks.md) # Enforce Transaction ShareLocks order (see docs: sharelocks.md)
order_by: [asc: :hash], order_by: [asc: :hash],
lock: "FOR UPDATE" lock: "FOR UPDATE"
@ -196,11 +166,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
updated_at: ^updated_at updated_at: ^updated_at
] ]
], ],
select: %{ select: s
block_hash: s.block_hash,
index: s.index,
hash: s.hash
}
) )
{_num, transactions} = repo.update_all(update_query, [], timeout: timeout) {_num, transactions} = repo.update_all(update_query, [], timeout: timeout)
@ -379,13 +345,27 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
defp remove_nonconsensus_internal_transactions(repo, forked_transaction_hashes, %{timeout: timeout}) do defp remove_nonconsensus_internal_transactions(repo, forked_transaction_hashes, %{timeout: timeout}) do
query = query =
from(internal_transaction in InternalTransaction, from(
internal_transaction in InternalTransaction,
where: internal_transaction.transaction_hash in ^forked_transaction_hashes, where: internal_transaction.transaction_hash in ^forked_transaction_hashes,
select: map(internal_transaction, [:transaction_hash, :index]) select: %{transaction_hash: internal_transaction.transaction_hash},
# Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md)
order_by: [
internal_transaction.transaction_hash,
internal_transaction.index
],
lock: "FOR UPDATE"
) )
# ShareLocks order already enforced by `acquire_internal_transactions` (see docs: sharelocks.md) delete_query =
{_count, deleted_internal_transactions} = repo.delete_all(query, timeout: timeout) from(
i in InternalTransaction,
join: s in subquery(query),
on: i.transaction_hash == s.transaction_hash,
select: map(i, [:transaction_hash, :index])
)
{_count, deleted_internal_transactions} = repo.delete_all(delete_query, timeout: timeout)
{:ok, deleted_internal_transactions} {:ok, deleted_internal_transactions}
rescue rescue
@ -632,7 +612,8 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
b in Block.SecondDegreeRelation, b in Block.SecondDegreeRelation,
join: s in subquery(query), join: s in subquery(query),
on: b.nephew_hash == s.nephew_hash and b.uncle_hash == s.uncle_hash, on: b.nephew_hash == s.nephew_hash and b.uncle_hash == s.uncle_hash,
update: [set: [uncle_fetched_at: ^updated_at]] update: [set: [uncle_fetched_at: ^updated_at]],
select: map(b, [:nephew_hash, :uncle_hash, :index])
) )
try do try do
@ -645,24 +626,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
end end
end end
defp update_internal_transaction_block_number(repo, blocks_hashes) when is_list(blocks_hashes) do
query =
from(
internal_transaction in InternalTransaction,
join: transaction in Transaction,
on: internal_transaction.transaction_hash == transaction.hash,
join: block in Block,
on: block.hash == transaction.block_hash,
where: block.hash in ^blocks_hashes,
update: [set: [block_number: block.number]]
)
# ShareLocks order already enforced by `acquire_internal_transactions` (see docs: sharelocks.md)
{total, _} = repo.update_all(query, [])
{:ok, total}
end
defp where_forked(blocks_changes) when is_list(blocks_changes) do defp where_forked(blocks_changes) when is_list(blocks_changes) do
initial = from(t in Transaction, where: false) initial = from(t in Transaction, where: false)

@ -4,9 +4,10 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
""" """
require Ecto.Query require Ecto.Query
require Logger
alias Ecto.{Changeset, Multi, Repo} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Hash, Import, InternalTransaction, Transaction} alias Explorer.Chain.{Block, Hash, Import, InternalTransaction, Transaction}
alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
@ -52,32 +53,43 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
|> Multi.run(:acquire_transactions, fn repo, _ -> |> Multi.run(:acquire_transactions, fn repo, _ ->
acquire_transactions(repo, changes_list) acquire_transactions(repo, changes_list)
end) end)
|> Multi.run(:internal_transactions, fn repo, _ -> |> Multi.run(:internal_transactions, fn repo, %{acquire_transactions: transactions} ->
insert(repo, changes_list, insert_options) insert(repo, changes_list, transactions, insert_options)
end) end)
|> Multi.run(:internal_transactions_indexed_at_transactions, fn repo, %{acquire_transactions: transaction_hashes} -> |> Multi.run(:internal_transactions_indexed_at_transactions, fn repo, %{acquire_transactions: transactions} ->
update_transactions(repo, transaction_hashes, update_transactions_options) update_transactions(repo, transactions, update_transactions_options)
end) end)
|> Multi.run(
:remove_consensus_of_missing_transactions_blocks,
fn repo, %{internal_transactions: inserted} = results_map ->
# NOTE: for this to work it has to follow the runner `internal_transactions_indexed_at_blocks`
block_hashes = Map.get(results_map, :internal_transactions_indexed_at_blocks, [])
remove_consensus_of_missing_transactions_blocks(repo, block_hashes, changes_list, inserted)
end
)
end end
@impl Runner @impl Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert(Repo.t(), [map], %{ @spec insert(Repo.t(), [map], [Transaction.t()], %{
optional(:on_conflict) => Runner.on_conflict(), optional(:on_conflict) => Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: }) ::
{:ok, [%{index: non_neg_integer, transaction_hash: Hash.t()}]} {:ok, [%{index: non_neg_integer, transaction_hash: Hash.t()}]}
| {:error, [Changeset.t()]} | {:error, [Changeset.t()]}
defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) defp insert(repo, changes_list, transactions, %{timeout: timeout, timestamps: timestamps} = options)
when is_list(changes_list) do when is_list(changes_list) do
on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md) transactions_map = Map.new(transactions, &{&1.hash, &1})
ordered_changes_list = Enum.sort_by(changes_list, &{&1.transaction_hash, &1.index})
final_changes_list = reject_pending_transactions(ordered_changes_list, repo) final_changes_list =
changes_list
# Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md)
|> Enum.sort_by(&{&1.transaction_hash, &1.index})
|> reject_missing_transactions(transactions_map)
{:ok, internal_transactions} = {:ok, internal_transactions} =
Import.insert_changes_list( Import.insert_changes_list(
@ -86,16 +98,12 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
conflict_target: [:transaction_hash, :index], conflict_target: [:transaction_hash, :index],
for: InternalTransaction, for: InternalTransaction,
on_conflict: on_conflict, on_conflict: on_conflict,
returning: [:transaction_hash, :index], returning: true,
timeout: timeout, timeout: timeout,
timestamps: timestamps timestamps: timestamps
) )
{:ok, {:ok, internal_transactions}
for(
internal_transaction <- internal_transactions,
do: Map.take(internal_transaction, [:id, :index, :transaction_hash])
)}
end end
defp default_on_conflict do defp default_on_conflict do
@ -158,26 +166,28 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
from( from(
t in Transaction, t in Transaction,
where: t.hash in ^transaction_hashes, where: t.hash in ^transaction_hashes,
# do not consider pending transactions
where: not is_nil(t.block_hash), where: not is_nil(t.block_hash),
select: t.hash, select: map(t, [:hash, :block_hash, :block_number]),
# Enforce Transaction ShareLocks order (see docs: sharelocks.md) # Enforce Transaction ShareLocks order (see docs: sharelocks.md)
order_by: t.hash, order_by: t.hash,
lock: "FOR UPDATE" lock: "FOR UPDATE"
) )
hashes = repo.all(query) {:ok, repo.all(query)}
{:ok, hashes}
end end
defp update_transactions(repo, transaction_hashes, %{ defp update_transactions(repo, transactions, %{
timeout: timeout, timeout: timeout,
timestamps: timestamps timestamps: timestamps
}) })
when is_list(transaction_hashes) do when is_list(transactions) do
transaction_hashes = Enum.map(transactions, & &1.hash)
update_query = update_query =
from( from(
t in Transaction, t in Transaction,
# pending transactions are already excluded by `acquire_transactions`
where: t.hash in ^transaction_hashes, where: t.hash in ^transaction_hashes,
# ShareLocks order already enforced by `acquire_transactions` (see docs: sharelocks.md) # ShareLocks order already enforced by `acquire_transactions` (see docs: sharelocks.md)
update: [ update: [
@ -214,22 +224,51 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
end end
end end
defp reject_pending_transactions(ordered_changes_list, repo) do # If not using Parity this is not relevant
transaction_hashes = defp remove_consensus_of_missing_transactions_blocks(_, [], _, _), do: {:ok, []}
ordered_changes_list
|> Enum.map(& &1.transaction_hash)
|> Enum.dedup()
query = defp remove_consensus_of_missing_transactions_blocks(repo, block_hashes, changes_list, inserted) do
from(t in Transaction, inserted_block_numbers = MapSet.new(inserted, & &1.block_number)
where: t.hash in ^transaction_hashes,
where: is_nil(t.block_hash), missing_transactions_block_numbers =
select: t.hash changes_list
|> MapSet.new(& &1.block_number)
|> MapSet.difference(inserted_block_numbers)
|> MapSet.to_list()
update_query =
from(
b in Block,
where: b.number in ^missing_transactions_block_numbers,
where: b.hash in ^block_hashes,
# ShareLocks order already enforced by `internal_transactions_indexed_at_blocks` (see docs: sharelocks.md)
update: [set: [consensus: false, internal_transactions_indexed_at: nil]]
) )
pending_transactions = repo.all(query) try do
{_num, result} = repo.update_all(update_query, [])
Logger.debug(fn ->
[
"consensus removed from blocks with numbers: ",
inspect(missing_transactions_block_numbers),
" because of missing transactions"
]
end)
{:ok, result}
rescue
postgrex_error in Postgrex.Error ->
{:error, %{exception: postgrex_error, missing_transactions_block_numbers: missing_transactions_block_numbers}}
end
end
ordered_changes_list defp reject_missing_transactions(ordered_changes_list, transactions_map) do
|> Enum.reject(fn %{transaction_hash: hash} -> Enum.member?(pending_transactions, hash) end) Enum.reject(ordered_changes_list, fn %{transaction_hash: hash} ->
transactions_map
|> Map.get(hash, %{})
|> Map.get(:block_hash)
|> is_nil()
end)
end end
end end

@ -65,12 +65,10 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsIndexedAtBlocks do
lock: "FOR UPDATE" lock: "FOR UPDATE"
) )
block_count = Enum.count(block_numbers)
try do try do
{^block_count, result} = {_, result} =
repo.update_all( repo.update_all(
from(b in Block, join: s in subquery(query), on: b.hash == s.hash), from(b in Block, join: s in subquery(query), on: b.hash == s.hash, select: b.hash),
[set: [internal_transactions_indexed_at: timestamps.updated_at]], [set: [internal_transactions_indexed_at: timestamps.updated_at]],
timeout: timeout timeout: timeout
) )

@ -69,7 +69,8 @@ defmodule Explorer.SmartContract.Verifier do
blockchain_bytecode_without_whisper = extract_bytecode(blockchain_bytecode) blockchain_bytecode_without_whisper = extract_bytecode(blockchain_bytecode)
cond do cond do
generated_bytecode != blockchain_bytecode_without_whisper -> generated_bytecode != blockchain_bytecode_without_whisper &&
!try_library_verification(generated_bytecode, blockchain_bytecode_without_whisper) ->
{:error, :generated_bytecode} {:error, :generated_bytecode}
has_constructor_with_params?(abi) && has_constructor_with_params?(abi) &&
@ -81,6 +82,18 @@ defmodule Explorer.SmartContract.Verifier do
end end
end end
# 730000000000000000000000000000000000000000 - default library address that returned by the compiler
defp try_library_verification(
"730000000000000000000000000000000000000000" <> bytecode,
<<_address::binary-size(42)>> <> bytecode
) do
true
end
defp try_library_verification(_, _) do
false
end
@doc """ @doc """
In order to discover the bytecode we need to remove the `swarm source` from In order to discover the bytecode we need to remove the `swarm source` from
the hash. the hash.

@ -0,0 +1,17 @@
defmodule Explorer.Chain.Cache.PendingTransactionsTest do
use Explorer.DataCase
alias Explorer.Chain.Cache.PendingTransactions
describe "update_pending/1" do
test "adds a new pending transaction" do
transaction = insert(:transaction, block_hash: nil, error: nil)
PendingTransactions.update([transaction])
transaction_hash = transaction.hash
assert [%{hash: transaction_hash}] = PendingTransactions.all()
end
end
end

@ -0,0 +1,28 @@
defmodule Explorer.Chain.Cache.UnclesTest do
use Explorer.DataCase
alias Explorer.Chain.Cache.Uncles
alias Explorer.Repo
setup do
Supervisor.terminate_child(Explorer.Supervisor, Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Uncles.child_id())
:ok
end
describe "update_from_second_degree_relations/1" do
test "fetches an uncle from a second_degree_relation and adds it to the cache" do
block = insert(:block)
uncle = insert(:block, consensus: false)
uncle_hash = uncle.hash
second_degree_relation = insert(:block_second_degree_relation, uncle_hash: uncle_hash, nephew: block)
Uncles.update_from_second_degree_relations([second_degree_relation])
assert [%{hash: uncle_hash}] = Uncles.all()
end
end
end

@ -2,7 +2,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
use Explorer.DataCase use Explorer.DataCase
alias Ecto.Multi alias Ecto.Multi
alias Explorer.Chain.{Data, Wei, Transaction, InternalTransaction} alias Explorer.Chain.{Block, Data, Wei, Transaction, InternalTransaction}
alias Explorer.Chain.Import.Runner.InternalTransactions alias Explorer.Chain.Import.Runner.InternalTransactions
describe "run/1" do describe "run/1" do
@ -42,10 +42,78 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
assert is_nil(Repo.get(Transaction, pending.hash).block_hash) assert is_nil(Repo.get(Transaction, pending.hash).block_hash)
end end
test "removes consensus to blocks where transactions are missing" do
empty_block = insert(:block)
pending = insert(:transaction)
assert is_nil(pending.block_hash)
full_block = insert(:block)
inserted = insert(:transaction) |> with_block(full_block)
assert full_block.hash == inserted.block_hash
index = 0
pending_transaction_changes =
pending.hash
|> make_internal_transaction_changes(index, nil)
|> Map.put(:block_number, empty_block.number)
transaction_changes =
inserted.hash
|> make_internal_transaction_changes(index, nil)
|> Map.put(:block_number, full_block.number)
multi =
Multi.new()
|> Multi.run(:internal_transactions_indexed_at_blocks, fn _, _ -> {:ok, [empty_block.hash, full_block.hash]} end)
assert {:ok, _} = run_internal_transactions([pending_transaction_changes, transaction_changes], multi)
assert from(i in InternalTransaction, where: i.transaction_hash == ^pending.hash) |> Repo.one() |> is_nil()
assert %{consensus: false} = Repo.get(Block, empty_block.hash)
assert from(i in InternalTransaction, where: i.transaction_hash == ^inserted.hash) |> Repo.one() |> is_nil() ==
false
assert %{consensus: true} = Repo.get(Block, full_block.hash)
end
test "does not remove consensus when block is empty and no transactions are missing" do
empty_block = insert(:block)
full_block = insert(:block)
inserted = insert(:transaction) |> with_block(full_block)
assert full_block.hash == inserted.block_hash
index = 0
transaction_changes =
inserted.hash
|> make_internal_transaction_changes(index, nil)
|> Map.put(:block_number, full_block.number)
multi =
Multi.new()
|> Multi.run(:internal_transactions_indexed_at_blocks, fn _, _ -> {:ok, [empty_block.hash, full_block.hash]} end)
assert {:ok, _} = run_internal_transactions([transaction_changes], multi)
assert %{consensus: true} = Repo.get(Block, empty_block.hash)
assert from(i in InternalTransaction, where: i.transaction_hash == ^inserted.hash) |> Repo.one() |> is_nil() ==
false
assert %{consensus: true} = Repo.get(Block, full_block.hash)
end
end end
defp run_internal_transactions(changes_list) when is_list(changes_list) do defp run_internal_transactions(changes_list, multi \\ Multi.new()) when is_list(changes_list) do
Multi.new() multi
|> InternalTransactions.run(changes_list, %{ |> InternalTransactions.run(changes_list, %{
timeout: :infinity, timeout: :infinity,
timestamps: %{inserted_at: DateTime.utc_now(), updated_at: DateTime.utc_now()} timestamps: %{inserted_at: DateTime.utc_now(), updated_at: DateTime.utc_now()}

@ -144,6 +144,34 @@ defmodule Explorer.SmartContract.VerifierTest do
assert abi != nil assert abi != nil
end end
test "verifies a library" do
bytecode =
"0x7349f540c22cba15c47a08c235e20081474201a742301460806040526004361060335760003560e01c8063c2985578146038575b600080fd5b603e60b0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101560765781810151838201526020016060565b50505050905090810190601f16801560a25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080518082019091526003815262666f6f60e81b60208201529056fea265627a7a72315820174b282a3ef3b9778d79fbc2e4c36bc939c54dfaaaa51d3122ee6e648093844c64736f6c634300050b0032"
contract_address = insert(:contract_address, contract_code: bytecode)
code = """
pragma solidity 0.5.11;
library Foo {
function foo() external pure returns (string memory) {
return "foo";
}
}
"""
params = %{
"contract_source_code" => code,
"compiler_version" => "v0.5.11+commit.c082d0b4",
"evm_version" => "default",
"name" => "Foo",
"optimization" => true
}
assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
assert abi != nil
end
test "verifies smart contract compiled with Solidity 0.5.9 (includes new metadata in bytecode) with constructor args" do test "verifies smart contract compiled with Solidity 0.5.9 (includes new metadata in bytecode) with constructor args" do
path = File.cwd!() <> "/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol" path = File.cwd!() <> "/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol"
contract = File.read!(path) contract = File.read!(path)

@ -47,6 +47,8 @@ defmodule Explorer.DataCase do
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Accounts.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.PendingTransactions.child_id())
:ok :ok
end end

@ -13,7 +13,7 @@ defmodule Indexer.Block.Fetcher do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Address, Block, Hash, Import, Transaction} alias Explorer.Chain.{Address, Block, Hash, Import, Transaction}
alias Explorer.Chain.Cache.Blocks, as: BlocksCache alias Explorer.Chain.Cache.Blocks, as: BlocksCache
alias Explorer.Chain.Cache.{Accounts, BlockNumber, Transactions} alias Explorer.Chain.Cache.{Accounts, BlockNumber, PendingTransactions, Transactions, Uncles}
alias Indexer.Block.Fetcher.Receipts alias Indexer.Block.Fetcher.Receipts
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
@ -175,8 +175,9 @@ defmodule Indexer.Block.Fetcher do
) do ) do
result = {:ok, %{inserted: inserted, errors: blocks_errors}} result = {:ok, %{inserted: inserted, errors: blocks_errors}}
update_block_cache(inserted[:blocks]) update_block_cache(inserted[:blocks])
update_transactions_cache(inserted[:transactions]) update_transactions_cache(inserted[:transactions], inserted[:fork_transactions])
update_addresses_cache(inserted[:addresses]) update_addresses_cache(inserted[:addresses])
update_uncles_cache(inserted[:block_second_degree_relations])
result result
else else
{step, {:error, reason}} -> {:error, {step, reason}} {step, {:error, reason}} -> {:error, {step, reason}}
@ -184,6 +185,8 @@ defmodule Indexer.Block.Fetcher do
end end
end end
defp update_block_cache([]), do: :ok
defp update_block_cache(blocks) when is_list(blocks) do defp update_block_cache(blocks) when is_list(blocks) do
{min_block, max_block} = Enum.min_max_by(blocks, & &1.number) {min_block, max_block} = Enum.min_max_by(blocks, & &1.number)
@ -194,12 +197,18 @@ defmodule Indexer.Block.Fetcher do
defp update_block_cache(_), do: :ok defp update_block_cache(_), do: :ok
defp update_transactions_cache(transactions) do defp update_transactions_cache(transactions, forked_transactions) do
Transactions.update(transactions) Transactions.update(transactions)
PendingTransactions.update_pending(transactions)
PendingTransactions.update_pending(forked_transactions)
end end
defp update_addresses_cache(addresses), do: Accounts.drop(addresses) defp update_addresses_cache(addresses), do: Accounts.drop(addresses)
defp update_uncles_cache(updated_relations) do
Uncles.update_from_second_degree_relations(updated_relations)
end
def import( def import(
%__MODULE__{broadcast: broadcast, callback_module: callback_module} = state, %__MODULE__{broadcast: broadcast, callback_module: callback_module} = state,
options options

@ -14,7 +14,7 @@ defmodule Indexer.Fetcher.PendingTransaction do
alias Ecto.Changeset alias Ecto.Changeset
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Cache.{Accounts, PendingTransactions}
alias Indexer.Fetcher.PendingTransaction alias Indexer.Fetcher.PendingTransaction
alias Indexer.Transform.Addresses alias Indexer.Transform.Addresses
@ -151,6 +151,7 @@ defmodule Indexer.Fetcher.PendingTransaction do
}) do }) do
{:ok, imported} -> {:ok, imported} ->
Accounts.drop(imported[:addresses]) Accounts.drop(imported[:addresses])
PendingTransactions.update_pending(imported[:transactions])
:ok :ok
{:error, [%Changeset{} | _] = changesets} -> {:error, [%Changeset{} | _] = changesets} ->

@ -12,7 +12,7 @@ defmodule Indexer.Fetcher.UncleBlock do
alias Ecto.Changeset alias Ecto.Changeset
alias EthereumJSONRPC.Blocks alias EthereumJSONRPC.Blocks
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Cache.{Accounts, PendingTransactions, Uncles}
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Indexer.{Block, BufferedTask, Tracer} alias Indexer.{Block, BufferedTask, Tracer}
alias Indexer.Fetcher.UncleBlock alias Indexer.Fetcher.UncleBlock
@ -129,6 +129,7 @@ defmodule Indexer.Fetcher.UncleBlock do
}) do }) do
{:ok, imported} -> {:ok, imported} ->
Accounts.drop(imported[:addresses]) Accounts.drop(imported[:addresses])
Uncles.update_from_second_degree_relations(imported[:block_second_degree_relations])
retry(errors) retry(errors)
{:error, {:import = step, [%Changeset{} | _] = changesets}} -> {:error, {:import = step, [%Changeset{} | _] = changesets}} ->
@ -155,7 +156,7 @@ defmodule Indexer.Fetcher.UncleBlock do
@impl Block.Fetcher @impl Block.Fetcher
def import(_, options) when is_map(options) do def import(_, options) when is_map(options) do
with {:ok, %{block_second_degree_relations: block_second_degree_relations}} = ok <- with {:ok, %{block_second_degree_relations: block_second_degree_relations} = imported} <-
options options
|> Map.drop(@ignored_options) |> Map.drop(@ignored_options)
|> uncle_blocks() |> uncle_blocks()
@ -168,8 +169,10 @@ defmodule Indexer.Fetcher.UncleBlock do
# * TokenBalance.async_fetch is not called because it uses block numbers from consensus, not uncles # * TokenBalance.async_fetch is not called because it uses block numbers from consensus, not uncles
UncleBlock.async_fetch_blocks(block_second_degree_relations) UncleBlock.async_fetch_blocks(block_second_degree_relations)
PendingTransactions.update_pending(imported[:transactions])
PendingTransactions.update_pending(imported[:fork_transactions])
ok {:ok, imported}
end end
end end

@ -15,6 +15,7 @@ defmodule Indexer.Temporary.UnclesWithoutIndex do
alias EthereumJSONRPC.Blocks alias EthereumJSONRPC.Blocks
alias Explorer.{Chain, Repo} alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.SecondDegreeRelation alias Explorer.Chain.Block.SecondDegreeRelation
alias Explorer.Chain.Cache.Uncles
alias Indexer.{BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.UncleBlock alias Indexer.Fetcher.UncleBlock
@ -99,6 +100,7 @@ defmodule Indexer.Temporary.UnclesWithoutIndex do
case Chain.import(%{block_second_degree_relations: %{params: block_second_degree_relations_params}}) do case Chain.import(%{block_second_degree_relations: %{params: block_second_degree_relations_params}}) do
{:ok, %{block_second_degree_relations: block_second_degree_relations}} -> {:ok, %{block_second_degree_relations: block_second_degree_relations}} ->
UncleBlock.async_fetch_blocks(block_second_degree_relations) UncleBlock.async_fetch_blocks(block_second_degree_relations)
Uncles.update_from_second_degree_relations(block_second_degree_relations)
retry(errors) retry(errors)

@ -39,7 +39,7 @@
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.6.4", "5b1ac8451f889576bb29dee70412de1170974298727ab944aa4d17e91bdd3472", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.3", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.6.4", "5b1ac8451f889576bb29dee70412de1170974298727ab944aa4d17e91bdd3472", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.3", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_units": {:hex, :ex_cldr_units, "2.5.1", "0e65067a22a7c5146266c313d6333c2700868c32aa6d536f47c6c0d84aac3ac1", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.2", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.6", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr_units": {:hex, :ex_cldr_units, "2.5.1", "0e65067a22a7c5146266c313d6333c2700868c32aa6d536f47c6c0d84aac3ac1", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.2", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.6", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.3", "3c7b0f02851f5fc13b040e8e925051452e41248f685e40250d7e40b07b9f8c10", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.3", "3c7b0f02851f5fc13b040e8e925051452e41248f685e40250d7e40b07b9f8c10", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_json_schema": {:hex, :ex_json_schema, "0.6.1", "b57c0588385b8262b80f19d33d9b9b71fcd60d247691abf2635b57a03ec0ad44", [:mix], [], "hexpm"}, "ex_json_schema": {:hex, :ex_json_schema, "0.6.2", "de23d80478215987469c81688208fe0ff440ee0e0e6ae2268fcadbb2ff35df9d", [:mix], [], "hexpm"},
"ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
"ex_rlp": {:hex, :ex_rlp, "0.5.2", "7f4ce7bd55e543c054ce6d49629b01e9833c3462e3d547952be89865f39f2c58", [:mix], [], "hexpm"}, "ex_rlp": {:hex, :ex_rlp, "0.5.2", "7f4ce7bd55e543c054ce6d49629b01e9833c3462e3d547952be89865f39f2c58", [:mix], [], "hexpm"},
"ex_utils": {:hex, :ex_utils, "0.1.7", "2c133e0bcdc49a858cf8dacf893308ebc05bc5fba501dc3d2935e65365ec0bf3", [:mix], [], "hexpm"}, "ex_utils": {:hex, :ex_utils, "0.1.7", "2c133e0bcdc49a858cf8dacf893308ebc05bc5fba501dc3d2935e65365ec0bf3", [:mix], [], "hexpm"},

Loading…
Cancel
Save