Merge branch 'master' into ab-pagination

pull/1974/head
Ayrat Badykov 6 years ago committed by GitHub
commit 39b180ccf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .circleci/config.yml
  2. 6
      CHANGELOG.md
  3. 49
      apps/block_scout_web/assets/css/theme/_ether1_variables.scss
  4. 1
      apps/block_scout_web/assets/css/theme/_variables.scss
  5. 44
      apps/block_scout_web/assets/static/images/ether1_logo.svg
  6. 4
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex
  7. 19
      apps/block_scout_web/lib/block_scout_web/etherscan.ex
  8. 12
      apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex
  9. 2
      apps/block_scout_web/mix.exs
  10. 28
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
  11. 20
      apps/block_scout_web/test/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller_test.exs
  12. 156
      apps/explorer/lib/explorer/chain.ex
  13. 4
      apps/explorer/lib/explorer/chain/address.ex
  14. 14
      apps/explorer/lib/explorer/chain/import/runner/addresses.ex
  15. 26
      apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
  16. 2
      apps/explorer/lib/explorer/smart_contract/solc_downloader.ex
  17. 14
      apps/explorer/priv/repo/migrations/20190516140202_add_address_hash_index_to_decompiled_smart_contracts.exs
  18. 18
      apps/explorer/priv/repo/migrations/20190516160535_add_decompiled_and_verified_flag_to_addresses.exs
  19. 6
      apps/explorer/test/explorer/chain_test.exs
  20. 5
      apps/explorer/test/support/factory.ex
  21. 3
      docker/Makefile
  22. 2
      mix.lock

@ -480,7 +480,7 @@ jobs:
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: mix test --exclude no_geth
name: mix test --exclude no_parity
command: |
# Don't submit coverage report for forks, but let the build succeed
if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then
@ -534,7 +534,7 @@ jobs:
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: mix test --exclude no_geth
name: mix test --exclude no_parity
command: |
# Don't submit coverage report for forks, but let the build succeed
if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then

@ -1,4 +1,5 @@
## Current
- [#2000](https://github.com/poanetwork/blockscout/pull/2000) - docker/Makefile: always set a container name
### Features
- [#1963](https://github.com/poanetwork/blockscout/pull/1963) - added rinkeby theme and rinkeby logo
@ -26,8 +27,10 @@
- [#1956](https://github.com/poanetwork/blockscout/pull/1956) - add logs tab to address
- [#1933](https://github.com/poanetwork/blockscout/pull/1933) - add eth_BlockNumber json rpc method
- [#1952](https://github.com/poanetwork/blockscout/pull/1952) - feat: exclude empty contracts by default
- [#1989](https://github.com/poanetwork/blockscout/pull/1989) - fix: consolidate address w/ balance one at a time
- [#1954](https://github.com/poanetwork/blockscout/pull/1954) - feat: use creation init on self destruct
- [#1974](https://github.com/poanetwork/blockscout/pull/1974) - feat: previous page button logic
- [#2002](https://github.com/poanetwork/blockscout/pull/2002) - Get estimated count of blocks when cache is empty
### Fixes
@ -52,6 +55,8 @@
- [#1937](https://github.com/poanetwork/blockscout/pull/1937) - Check the presence of overlap[i] object before retrieving properties from it
- [#1960](https://github.com/poanetwork/blockscout/pull/1960) - do not remove bold text in decompiled contacts
- [#1917](https://github.com/poanetwork/blockscout/pull/1917) - Force block refetch if transaction is re-collated in a different block
- [#1992](https://github.com/poanetwork/blockscout/pull/1992) - fix: support https for wobserver polling
- [#1966](https://github.com/poanetwork/blockscout/pull/1966) - fix: add fields for contract filter performance
### Chore
@ -61,6 +66,7 @@
- [#1892](https://github.com/poanetwork/blockscout/pull/1892) - Remove temporary worker modules
- [#1958](https://github.com/poanetwork/blockscout/pull/1958) - Default value for release link env var
- [#1975](https://github.com/poanetwork/blockscout/pull/1975) - add log index to transaction view
- [#1988](https://github.com/poanetwork/blockscout/pull/1988) - Fix wrong parity tasks names in Circle CI
## 1.3.10-beta

@ -0,0 +1,49 @@
// general
$primary: #840032;
$secondary: #343434;
$tertiary: #7f7f7f;
$additional-font: #ff95db;
// footer
$footer-background-color: $primary;
$footer-title-color: #fff;
$footer-text-color: #fff;
$footer-item-disc-color: $secondary;
// dashboard
$dashboard-line-color-price: $tertiary; // price left border
$dashboard-banner-chart-legend-value-color: $additional-font; // chart labels
$dashboard-stats-item-value-color: $additional-font; // stat values
$dashboard-stats-item-border-color: $secondary; // stat border
$dashboard-banner-gradient-start: $primary; // gradient begin
$dashboard-banner-gradient-end: lighten($primary, 5); // gradient end
$dashboard-banner-network-plain-container-background-color: #4b021e; // stats bg
// navigation
.navbar { box-shadow: 0px 0px 30px 0px rgba(75, 2, 30, 0.12); } // header shadow
$header-icon-border-color-hover: $tertiary; // top border on hover
$header-icon-color-hover: $tertiary; // nav icon on hover
.dropdown-item:hover, .dropdown-item:focus { background-color: $tertiary !important; } // dropdown item on hover
// buttons
$btn-line-bg: #fff; // button bg
$btn-line-color: #4b021e; // button border and font color && hover bg color
$btn-copy-color: #4b021e; // btn copy
$btn-qr-color: #4b021e; // btn qr-code
//links & tile
.tile a { color: $tertiary !important; } // links color for badges
.tile-type-block {
border-left: 4px solid #4b021e;
} // tab active bg
// card
$card-background-1: $tertiary;
$card-tab-active: $tertiary;

@ -3,6 +3,7 @@
// @import "dai_variables";
// @import "ethereum_classic_variables";
// @import "ethereum_variables";
// @import "ether1_variables";
// @import "expanse_variables";
// @import "gochain_variables";
// @import "goerli_variables";

@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 681.502">
<linearGradient id="a" x1="92.465" x2="99.047" y1="689.896" y2="446.357" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset=".19" stop-color="#e2e2e2"/>
<stop offset=".589" stop-color="#d5d5d5"/>
<stop offset=".868" stop-color="#c6c6c6"/>
<stop offset="1" stop-color="#b7b7b7"/>
</linearGradient>
<path fill="url(#a)" d="M191.506 496.463L1.681 392.807l189.825 288.695z"/>
<linearGradient id="b" x1="246.495" x2="109.916" y1="458.546" y2="613.226" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<path fill="url(#b)" d="M191.506 496.463l-81.21-44.346 81.21 229.385z" opacity=".5"/>
<linearGradient id="c" x1="296.634" x2="303.216" y1="695.414" y2="451.875" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset=".19" stop-color="#e2e2e2"/>
<stop offset=".589" stop-color="#cfcfcf"/>
<stop offset=".868" stop-color="#ccc"/>
<stop offset="1" stop-color="#bababa"/>
</linearGradient>
<path fill="url(#c)" d="M208.501 681.502l189.821-288.695-189.821 103.656z"/>
<linearGradient id="d" x1="162.391" x2="326.945" y1="6.627" y2="477.251" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset=".19" stop-color="#e2e2e2"/>
<stop offset=".589" stop-color="#ccc"/>
<stop offset=".868" stop-color="#bdbdbd"/>
<stop offset="1" stop-color="#a3a3a3"/>
</linearGradient>
<path fill="url(#d)" d="M400 346.41L200.003.006v453.968z"/>
<linearGradient id="e" x1="-50.463" x2="215.339" y1="226.987" y2="226.987" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset=".19" stop-color="#efefef"/>
<stop offset=".589" stop-color="#cfcfcf"/>
<stop offset=".868" stop-color="#c6c6c6"/>
<stop offset="1" stop-color="#c6c6c6"/>
</linearGradient>
<path fill="url(#e)" d="M200 0L0 346.41l200 107.564h.003V.006z"/>
<linearGradient id="f" x1="254.812" x2="91.355" y1="159.307" y2="361.159" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<path fill="url(#f)" d="M120.273 138.091L200.003.006v453.968z" opacity=".5"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -98,10 +98,10 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
Chain.list_decompiled_contracts(page_size, offset, not_decompiled_with_version)
:unverified ->
Chain.list_unverified_contracts(page_size, offset)
Chain.list_unordered_unverified_contracts(page_size, offset)
:not_decompiled ->
Chain.list_not_decompiled_contracts(page_size, offset)
Chain.list_unordered_not_decompiled_contracts(page_size, offset)
:empty ->
Chain.list_empty_contracts(page_size, offset)

@ -862,11 +862,6 @@ defmodule BlockScoutWeb.Etherscan do
name: "Contract",
fields: %{
"Address" => @address_hash_type,
"DecompilerVersion" => %{
type: "decompiler version",
definition: "When decompiled source code is present, the decompiler version with which it was generated.",
example: "decompiler.version"
},
"ABI" => %{
type: "ABI",
definition: "JSON string for the contract's Application Binary Interface (ABI)",
@ -938,9 +933,16 @@ defmodule BlockScoutWeb.Etherscan do
"""
}
@contract_decompiler_version_type %{
type: "decompiler version",
definition: "When decompiled source code is present, the decompiler version with which it was generated.",
example: "decompiler.version"
}
@contract_with_sourcecode_model @contract_model
|> put_in([:fields, "SourceCode"], @contract_source_code_type)
|> put_in([:fields, "DecompiledSourceCode"], @contract_decompiled_source_code_type)
|> put_in([:fields, "DecompilerVersion"], @contract_decompiler_version_type)
@transaction_receipt_status_model %{
name: "TransactionReceiptStatus",
@ -1831,7 +1833,12 @@ defmodule BlockScoutWeb.Etherscan do
@contract_listcontracts_action %{
name: "listcontracts",
description: "Get a list of contracts, sorted ascending by the time they were first seen by the explorer.",
description: """
Get a list of contracts, sorted ascending by the time they were first seen by the explorer.
If you provide the filters `not_decompiled`(`4`) or `not_verified(4)` the results will not
be sorted for performance reasons.
""",
required_params: [],
optional_params: [
%{

@ -76,16 +76,12 @@ defmodule BlockScoutWeb.API.RPC.ContractView do
defp prepare_contract(%Address{
hash: hash,
smart_contract: nil,
decompiled_smart_contracts: decompiled_smart_contracts
smart_contract: nil
}) do
decompiled_smart_contract = latest_decompiled_smart_contract(decompiled_smart_contracts)
%{
"Address" => to_string(hash),
"ABI" => "Contract source code not verified",
"ContractName" => "",
"DecompilerVersion" => decompiler_version(decompiled_smart_contract),
"CompilerVersion" => "",
"OptimizationUsed" => ""
}
@ -93,16 +89,12 @@ defmodule BlockScoutWeb.API.RPC.ContractView do
defp prepare_contract(%Address{
hash: hash,
smart_contract: %SmartContract{} = contract,
decompiled_smart_contracts: decompiled_smart_contracts
smart_contract: %SmartContract{} = contract
}) do
decompiled_smart_contract = latest_decompiled_smart_contract(decompiled_smart_contracts)
%{
"Address" => to_string(hash),
"ABI" => Jason.encode!(contract.abi),
"ContractName" => contract.name,
"DecompilerVersion" => decompiler_version(decompiled_smart_contract),
"CompilerVersion" => contract.compiler_version,
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}

@ -128,7 +128,7 @@ defmodule BlockScoutWeb.Mixfile do
{:timex, "~> 3.4"},
{:wallaby, "~> 0.22", only: [:test], runtime: false},
# `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility
{:wobserver, "~> 0.2.0", github: "KronicDeth/wobserver", ref: "99683a936c75c0a94ebb884cef019f7ed0b97112"},
{:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"},
{:phoenix_form_awesomplete, "~> 0.1.4"}
]
end

@ -47,7 +47,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(contract.address_hash),
"CompilerVersion" => contract.compiler_version,
"ContractName" => contract.name,
"DecompilerVersion" => "",
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}
]
@ -70,7 +69,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(address.hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "",
"OptimizationUsed" => ""
}
]
@ -94,7 +92,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(address.hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "",
"OptimizationUsed" => ""
}
]
@ -122,7 +119,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(address.hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "",
"OptimizationUsed" => ""
}
]
@ -145,7 +141,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"ABI" => Jason.encode!(contract.abi),
"Address" => to_string(contract.address_hash),
"CompilerVersion" => contract.compiler_version,
"DecompilerVersion" => "",
"ContractName" => contract.name,
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}
@ -170,7 +165,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(decompiled_smart_contract.address_hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "test_decompiler",
"OptimizationUsed" => ""
}
]
@ -194,7 +188,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(smart_contract.address_hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "bizbuz",
"OptimizationUsed" => ""
}
]
@ -214,16 +207,15 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(smart_contract.address_hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "bizbuz",
"OptimizationUsed" => ""
}
]
assert %{
"ABI" => "Contract source code not verified",
"Address" => to_string(smart_contract.address_hash),
"CompilerVersion" => "",
"ContractName" => "",
"OptimizationUsed" => ""
} in response["result"]
refute to_string(non_match.address_hash) in Enum.map(response["result"], &Map.get(&1, "Address"))
end
test "filtering for only not_decompiled (and by extension not verified contracts)", %{params: params, conn: conn} do
@ -245,7 +237,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(contract_address.hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "",
"OptimizationUsed" => ""
}
]
@ -274,7 +265,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"Address" => to_string(contract_address.hash),
"CompilerVersion" => "",
"ContractName" => "",
"DecompilerVersion" => "",
"OptimizationUsed" => ""
}
]

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.API.V1.DecompiledControllerTest do
use BlockScoutWeb.ConnCase
alias Explorer.Repo
alias Explorer.Chain.DecompiledSmartContract
alias Explorer.Chain.{Address, DecompiledSmartContract}
import Ecto.Query,
only: [from: 2]
@ -87,6 +87,24 @@ defmodule BlockScoutWeb.API.V1.DecompiledControllerTest do
assert decompiled_smart_contract.decompiler_version == decompiler_version
assert decompiled_smart_contract.decompiled_source_code == decompiled_source_code
end
test "updates the address to be decompiled", %{conn: conn} do
address_hash = to_string(insert(:address, hash: "0x0000000000000000000000000000000000000001").hash)
decompiler_version = "test_decompiler"
decompiled_source_code = "hello world"
params = %{
"address_hash" => address_hash,
"decompiler_version" => decompiler_version,
"decompiled_source_code" => decompiled_source_code
}
request = post(conn, api_v1_decompiled_smart_contract_path(conn, :create), params)
assert request.status == 201
assert Repo.get!(Address, address_hash).decompiled
end
end
describe "when user is not authorized" do

@ -363,21 +363,6 @@ defmodule Explorer.Chain do
Repo.aggregate(Block, :count, :hash)
end
@doc """
The number of consensus blocks.
iex> insert(:block, consensus: true)
iex> insert(:block, consensus: false)
iex> Explorer.Chain.block_consensus_count()
1
"""
def block_consensus_count do
Block
|> where(consensus: true)
|> Repo.aggregate(:count, :hash)
end
@doc """
Reward for mining a block.
@ -569,9 +554,19 @@ defmodule Explorer.Chain do
@spec create_decompiled_smart_contract(map()) :: {:ok, Address.t()} | {:error, Ecto.Changeset.t()}
def create_decompiled_smart_contract(attrs) do
%DecompiledSmartContract{}
|> DecompiledSmartContract.changeset(attrs)
|> Repo.insert(on_conflict: :replace_all, conflict_target: [:decompiler_version, :address_hash])
changeset = DecompiledSmartContract.changeset(%DecompiledSmartContract{}, attrs)
Multi.new()
|> Multi.insert(:decompiled_smart_contract, changeset,
on_conflict: :replace_all,
conflict_target: [:decompiler_version, :address_hash]
)
|> Multi.run(:set_address_decompiled, &set_address_decompiled/2)
|> Repo.transaction()
|> case do
{:ok, %{decompiled_smart_contract: decompiled_smart_contract}} -> {:ok, decompiled_smart_contract}
{:error, _, error_value, _} -> {:error, error_value}
end
end
@doc """
@ -1997,7 +1992,9 @@ defmodule Explorer.Chain do
cached_value = BlockCountCache.count()
if is_nil(cached_value) do
block_consensus_count()
%Postgrex.Result{rows: [[count]]} = Repo.query!("SELECT reltuples FROM pg_class WHERE relname = 'blocks';")
trunc(count * 0.90)
else
cached_value
end
@ -2248,6 +2245,7 @@ defmodule Explorer.Chain do
|> Multi.insert(:smart_contract, smart_contract_changeset)
|> Multi.run(:clear_primary_address_names, &clear_primary_address_names/2)
|> Multi.run(:insert_address_name, &create_address_name/2)
|> Multi.run(:set_address_verified, &set_address_verified/2)
|> Repo.transaction()
with {:ok, %{smart_contract: smart_contract}} <- insert_result do
@ -2255,6 +2253,35 @@ defmodule Explorer.Chain do
else
{:error, :smart_contract, changeset, _} ->
{:error, changeset}
{:error, :set_address_verified, message, _} ->
{:error, message}
end
end
defp set_address_verified(repo, %{smart_contract: %SmartContract{address_hash: address_hash}}) do
query =
from(
address in Address,
where: address.hash == ^address_hash
)
case repo.update_all(query, set: [verified: true]) do
{1, _} -> {:ok, []}
_ -> {:error, "There was an error annotating that the address has been verified."}
end
end
defp set_address_decompiled(repo, %{decompiled_smart_contract: %DecompiledSmartContract{address_hash: address_hash}}) do
query =
from(
address in Address,
where: address.hash == ^address_hash
)
case repo.update_all(query, set: [decompiled: true]) do
{1, _} -> {:ok, []}
_ -> {:error, "There was an error annotating that the address has been verified."}
end
end
@ -2767,50 +2794,46 @@ defmodule Explorer.Chain do
query =
from(
address in Address,
where:
fragment(
"EXISTS (SELECT 1 FROM decompiled_smart_contracts WHERE decompiled_smart_contracts.address_hash = ?)",
address.hash
),
preload: [:decompiled_smart_contracts, :smart_contract],
order_by: [asc: address.inserted_at],
where: address.contract_code != <<>>,
where: not is_nil(address.contract_code),
where: address.decompiled == true,
limit: ^limit,
offset: ^offset
offset: ^offset,
order_by: [asc: address.inserted_at],
preload: [:smart_contract]
)
query
|> filter_decompiled_with_version(not_decompiled_with_version)
|> reject_decompiled_with_version(not_decompiled_with_version)
|> Repo.all()
end
defp filter_decompiled_with_version(query, nil) do
query
end
defp reject_decompiled_with_version(query, nil), do: query
defp filter_decompiled_with_version(query, not_decompiled_with_version) do
from(address in query,
left_join: decompiled_smart_contract in DecompiledSmartContract,
on: decompiled_smart_contract.decompiler_version == ^not_decompiled_with_version,
on: decompiled_smart_contract.address_hash == address.hash,
where: is_nil(decompiled_smart_contract.id),
distinct: [address.hash]
defp reject_decompiled_with_version(query, reject_version) do
from(
address in query,
left_join: decompiled_smart_contract in assoc(address, :decompiled_smart_contracts),
on: decompiled_smart_contract.decompiler_version == ^reject_version,
where: is_nil(decompiled_smart_contract.address_hash)
)
end
def list_verified_contracts(limit, offset) do
query =
from(
address in Address,
where: not is_nil(address.contract_code),
join: smart_contract in SmartContract,
on: smart_contract.address_hash == address.hash,
preload: [{:smart_contract, smart_contract}, :decompiled_smart_contracts],
order_by: [asc: address.inserted_at],
smart_contract in SmartContract,
order_by: [asc: smart_contract.inserted_at],
limit: ^limit,
offset: ^offset
offset: ^offset,
preload: [:address]
)
Repo.all(query)
query
|> Repo.all()
|> Enum.map(fn smart_contract ->
Map.put(smart_contract.address, :smart_contract, smart_contract)
end)
end
def list_contracts(limit, offset) do
@ -2818,7 +2841,7 @@ defmodule Explorer.Chain do
from(
address in Address,
where: not is_nil(address.contract_code),
preload: [:smart_contract, :decompiled_smart_contracts],
preload: [:smart_contract],
order_by: [asc: address.inserted_at],
limit: ^limit,
offset: ^offset
@ -2827,22 +2850,22 @@ defmodule Explorer.Chain do
Repo.all(query)
end
def list_unverified_contracts(limit, offset) do
def list_unordered_unverified_contracts(limit, offset) do
query =
from(
address in Address,
left_join: smart_contract in SmartContract,
on: smart_contract.address_hash == address.hash,
where: not is_nil(address.contract_code),
where: is_nil(smart_contract.address_hash),
where: address.contract_code != <<>>,
preload: [{:smart_contract, smart_contract}, :decompiled_smart_contracts],
order_by: [asc: address.inserted_at],
where: not is_nil(address.contract_code),
where: fragment("? IS NOT TRUE", address.verified),
limit: ^limit,
offset: ^offset
)
Repo.all(query)
query
|> Repo.all()
|> Enum.map(fn address ->
%{address | smart_contract: nil}
end)
end
def list_empty_contracts(limit, offset) do
@ -2858,30 +2881,23 @@ defmodule Explorer.Chain do
Repo.all(query)
end
def list_not_decompiled_contracts(limit, offset) do
def list_unordered_not_decompiled_contracts(limit, offset) do
query =
from(
address in Address,
where:
fragment(
"NOT EXISTS (SELECT 1 FROM decompiled_smart_contracts WHERE decompiled_smart_contracts.address_hash = ?)",
address.hash
),
where: fragment("? IS NOT TRUE", address.verified),
where: fragment("? IS NOT TRUE", address.decompiled),
where: address.contract_code != <<>>,
left_join: smart_contract in SmartContract,
on: smart_contract.address_hash == address.hash,
left_join: decompiled_smart_contract in DecompiledSmartContract,
on: decompiled_smart_contract.address_hash == address.hash,
preload: [:smart_contract, :decompiled_smart_contracts],
where: not is_nil(address.contract_code),
where: is_nil(smart_contract.address_hash),
where: is_nil(decompiled_smart_contract.address_hash),
order_by: [asc: address.inserted_at],
limit: ^limit,
offset: ^offset
)
Repo.all(query)
query
|> Repo.all()
|> Enum.map(fn address ->
%{address | smart_contract: nil}
end)
end
@doc """

@ -22,7 +22,7 @@ defmodule Explorer.Chain.Address do
Wei
}
@optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number nonce)a
@optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number nonce decompiled verified)a
@required_attrs ~w(hash)a
@allowed_attrs @optional_attrs ++ @required_attrs
@ -75,6 +75,8 @@ defmodule Explorer.Chain.Address do
field(:fetched_coin_balance_block_number, :integer)
field(:contract_code, Data)
field(:nonce, :integer)
field(:decompiled, :boolean, default: false)
field(:verified, :boolean, default: false)
field(:has_decompiled_code?, :boolean, virtual: true)
field(:stale?, :boolean, virtual: true)

@ -13,6 +13,11 @@ defmodule Explorer.Chain.Import.Runner.Addresses do
@behaviour Import.Runner
@row_defaults %{
decompiled: false,
verified: false
}
# milliseconds
@timeout 60_000
@ -45,9 +50,16 @@ defmodule Explorer.Chain.Import.Runner.Addresses do
update_transactions_options = %{timeout: transactions_timeout, timestamps: timestamps}
changes_list_with_defaults =
Enum.map(changes_list, fn change ->
Enum.reduce(@row_defaults, change, fn {default_key, default_value}, acc ->
Map.put_new(acc, default_key, default_value)
end)
end)
multi
|> Multi.run(:addresses, fn repo, _ ->
insert(repo, changes_list, insert_options)
insert(repo, changes_list_with_defaults, insert_options)
end)
|> Multi.run(:created_address_code_indexed_at_transactions, fn repo, %{addresses: addresses}
when is_list(addresses) ->

@ -40,15 +40,10 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
end
@impl true
def init(args) do
def init(_args) do
create_table()
if enable_consolidation?() do
Task.start_link(&consolidate/0)
schedule_next_consolidation()
end
{:ok, args}
{:ok, %{consolidate?: enable_consolidation?()}, {:continue, :ok}}
end
def create_table do
@ -63,9 +58,7 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
end
defp schedule_next_consolidation do
if enable_consolidation?() do
Process.send_after(self(), :consolidate, :timer.seconds(@update_interval_in_seconds))
end
Process.send_after(self(), :consolidate, :timer.seconds(@update_interval_in_seconds))
end
@doc """
@ -75,6 +68,19 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
:ets.insert(table_name(), {key, info})
end
@impl true
def handle_continue(:ok, %{consolidate?: true} = state) do
consolidate()
schedule_next_consolidation()
{:noreply, state}
end
@impl true
def handle_continue(:ok, state) do
{:noreply, state}
end
@impl true
def handle_info(:consolidate, state) do
consolidate()

@ -86,7 +86,7 @@ defmodule Explorer.SmartContract.SolcDownloader do
download_path = "https://ethereum.github.io/solc-bin/bin/soljson-#{version}.js"
download_path
|> HTTPoison.get!([], timeout: 60_000)
|> HTTPoison.get!([], timeout: 60_000, recv_timeout: 60_000)
|> Map.get(:body)
end
end

@ -0,0 +1,14 @@
defmodule Explorer.Repo.Migrations.AddAddressHashIndexToDecompiledSmartContracts do
use Ecto.Migration
def change do
execute(
"""
CREATE INDEX IF NOT EXISTS decompiled_smart_contracts_address_hash_index ON decompiled_smart_contracts(address_hash);
""",
"""
DROP INDEX IF EXISTS decompiled_smart_contracts_address_hash_index
"""
)
end
end

@ -0,0 +1,18 @@
defmodule Explorer.Repo.Migrations.AddDecompiledAndVerifiedFlagToAddresses do
use Ecto.Migration
def change do
execute(
"""
ALTER TABLE addresses
ADD COLUMN IF NOT EXISTS decompiled BOOLEAN,
ADD COLUMN IF NOT EXISTS verified BOOLEAN;
""",
"""
ALTER TABLE addresses
DROP COLUMN IF EXISTS decompiled,
DROP COLUMN IF EXISTS verified;
"""
)
end
end

@ -2859,6 +2859,12 @@ defmodule Explorer.ChainTest do
assert {:ok, _} = Chain.create_smart_contract(attrs)
assert Repo.get_by(Address.Name, name: "SimpleStorage")
end
test "sets the address verified field to true", %{valid_attrs: valid_attrs} do
assert {:ok, %SmartContract{} = smart_contract} = Chain.create_smart_contract(valid_attrs)
assert Repo.get_by(Address, hash: smart_contract.address_hash).verified == true
end
end
describe "stream_unfetched_balances/2" do

@ -482,6 +482,7 @@ defmodule Explorer.Factory do
address = %Address{
hash: address_hash(),
verified: true,
contract_code: contract_code_info().bytecode,
smart_contract: smart_contract
}
@ -519,7 +520,7 @@ defmodule Explorer.Factory do
contract_code_info = contract_code_info()
%SmartContract{
address_hash: insert(:address, contract_code: contract_code_info.bytecode).hash,
address_hash: insert(:address, contract_code: contract_code_info.bytecode, verified: true).hash,
compiler_version: contract_code_info.version,
name: contract_code_info.name,
contract_source_code: contract_code_info.source_code,
@ -532,7 +533,7 @@ defmodule Explorer.Factory do
contract_code_info = contract_code_info()
%DecompiledSmartContract{
address_hash: insert(:address, contract_code: contract_code_info.bytecode).hash,
address_hash: insert(:address, contract_code: contract_code_info.bytecode, decompiled: true).hash,
decompiler_version: "test_decompiler",
decompiled_source_code: contract_code_info.source_code
}

@ -1,6 +1,7 @@
SYSTEM = $(shell uname -s)
HOST = host.docker.internal
DOCKER_IMAGE = blockscout_prod
BS_CONTAINER_NAME = blockscout
PG_CONTAINER_NAME = postgres
PG_CONTAINER_IMAGE = postgres:10.4
THIS_FILE = $(lastword $(MAKEFILE_LIST))
@ -87,7 +88,7 @@ endif
start: build postgres
@echo "==> Starting blockscout"
@docker run --rm \
@docker run --rm --name $(BS_CONTAINER_NAME) \
$(BLOCKSCOUT_CONTAINNER_PARAMS) \
-p 4000:4000 \
$(DOCKER_IMAGE) /bin/sh -c "mix phx.server"

@ -109,5 +109,5 @@
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
"wallaby": {:hex, :wallaby, "0.22.0", "e5d16bfa7ab23562c8a6e3b0a31445a2fd470ca622082a910114807ba823780d", [:mix], [{:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm"},
"websocket_client": {:hex, :websocket_client, "1.3.0", "2275d7daaa1cdacebf2068891c9844b15f4fdc3de3ec2602420c2fb486db59b6", [:rebar3], [], "hexpm"},
"wobserver": {:git, "https://github.com/KronicDeth/wobserver.git", "99683a936c75c0a94ebb884cef019f7ed0b97112", [ref: "99683a936c75c0a94ebb884cef019f7ed0b97112"]},
"wobserver": {:git, "https://github.com/poanetwork/wobserver.git", "13bcda30a87f4f0be1878920a79433ad831eefbe", [branch: "support-https"]},
}

Loading…
Cancel
Save