From e49412f38934a981b48e41fe8cc36a58229ee898 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 6 May 2019 10:23:07 +0300 Subject: [PATCH 01/11] remove temporary worker modules --- apps/indexer/lib/indexer/supervisor.ex | 4 - .../temporary/addresses_without_code.ex | 147 ------- .../temporary/failed_created_addresses.ex | 132 ------ .../temporary/addresses_without_code_test.exs | 389 ------------------ .../failed_created_addresses_test.exs | 78 ---- 5 files changed, 750 deletions(-) delete mode 100644 apps/indexer/lib/indexer/temporary/addresses_without_code.ex delete mode 100644 apps/indexer/lib/indexer/temporary/failed_created_addresses.ex delete mode 100644 apps/indexer/test/indexer/temporary/addresses_without_code_test.exs delete mode 100644 apps/indexer/test/indexer/temporary/failed_created_addresses_test.exs diff --git a/apps/indexer/lib/indexer/supervisor.ex b/apps/indexer/lib/indexer/supervisor.ex index 375a17e669..4e04b53092 100644 --- a/apps/indexer/lib/indexer/supervisor.ex +++ b/apps/indexer/lib/indexer/supervisor.ex @@ -24,8 +24,6 @@ defmodule Indexer.Supervisor do } alias Indexer.Temporary.{ - AddressesWithoutCode, - FailedCreatedAddresses, UncatalogedTokenTransfers, UnclesWithoutIndex } @@ -130,8 +128,6 @@ defmodule Indexer.Supervisor do {TokenUpdater.Supervisor, [%{update_interval: metadata_updater_inverval}]}, # Temporary workers - {AddressesWithoutCode.Supervisor, [fixing_realtime_fetcher]}, - {FailedCreatedAddresses.Supervisor, [json_rpc_named_arguments]}, {UncatalogedTokenTransfers.Supervisor, [[]]}, {UnclesWithoutIndex.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]} diff --git a/apps/indexer/lib/indexer/temporary/addresses_without_code.ex b/apps/indexer/lib/indexer/temporary/addresses_without_code.ex deleted file mode 100644 index 4aa36ce0b6..0000000000 --- a/apps/indexer/lib/indexer/temporary/addresses_without_code.ex +++ /dev/null @@ -1,147 +0,0 @@ -defmodule Indexer.Temporary.AddressesWithoutCode do - @moduledoc """ - Temporary module to fetch contract code for addresses without it. - """ - - use GenServer - use Indexer.Fetcher - - require Logger - - import Ecto.Query - - alias Explorer.Chain.{Address, Block, Transaction} - alias Explorer.Repo - alias Indexer.Block.Realtime.Fetcher - alias Indexer.Temporary.AddressesWithoutCode.TaskSupervisor - - @task_options [max_concurrency: 3, timeout: :infinity] - @batch_size 500 - @query_timeout :infinity - - def start_link([fetcher, gen_server_options]) do - GenServer.start_link(__MODULE__, fetcher, gen_server_options) - end - - @impl GenServer - def init(fetcher) do - schedule_work() - - {:ok, fetcher} - end - - def schedule_work do - Process.send_after(self(), :run, 1_000) - end - - @impl GenServer - def handle_info(:run, fetcher) do - run(fetcher) - - {:noreply, fetcher} - end - - def run(fetcher) do - fix_transaction_without_to_address_and_created_contract_address(fetcher) - fix_addresses_with_creation_transaction_but_without_code(fetcher) - end - - def fix_transaction_without_to_address_and_created_contract_address(fetcher) do - Logger.debug( - [ - "Started fix_transaction_without_to_address_and_created_contract_address" - ], - fetcher: :addresses_without_code - ) - - query = - from(block in Block, - left_join: transaction in Transaction, - on: block.hash == transaction.block_hash, - where: - is_nil(transaction.to_address_hash) and is_nil(transaction.created_contract_address_hash) and - block.consensus == true and is_nil(transaction.error) and not is_nil(transaction.hash), - distinct: block.hash - ) - - process_query(query, fetcher) - - Logger.debug( - [ - "Started fix_transaction_without_to_address_and_created_contract_address" - ], - fetcher: :addresses_without_code - ) - end - - def fix_addresses_with_creation_transaction_but_without_code(fetcher) do - Logger.debug( - [ - "Started fix_addresses_with_creation_transaction_but_without_code" - ], - fetcher: :addresses_without_code - ) - - second_query = - from(block in Block, - left_join: transaction in Transaction, - on: transaction.block_hash == block.hash, - left_join: address in Address, - on: address.hash == transaction.created_contract_address_hash, - where: - not is_nil(transaction.block_hash) and not is_nil(transaction.created_contract_address_hash) and - is_nil(address.contract_code) and - block.consensus == true and is_nil(transaction.error) and not is_nil(transaction.hash), - distinct: block.hash - ) - - process_query(second_query, fetcher) - - Logger.debug( - [ - "Finished fix_addresses_with_creation_transaction_but_without_code" - ], - fetcher: :addresses_without_code - ) - end - - defp process_query(query, fetcher) do - query_stream = Repo.stream(query, max_rows: @batch_size, timeout: @query_timeout) - - stream = - TaskSupervisor - |> Task.Supervisor.async_stream_nolink( - query_stream, - fn block -> refetch_block(block, fetcher) end, - @task_options - ) - - Repo.transaction(fn -> Stream.run(stream) end, timeout: @query_timeout) - end - - def refetch_block(block, fetcher) do - Logger.debug( - [ - "Processing block #{to_string(block.hash)} #{block.number}" - ], - fetcher: :addresses_without_code - ) - - Fetcher.fetch_and_import_block(block.number, fetcher, false) - - Logger.debug( - [ - "Finished processing block #{to_string(block.hash)} #{block.number}" - ], - fetcher: :addresses_without_code - ) - rescue - e -> - Logger.debug( - [ - "Failed to fetch block #{to_string(block.hash)} #{block.number} because of #{inspect(e)}" - ], - fetcher: :addresses_without_code - ) - end -end diff --git a/apps/indexer/lib/indexer/temporary/failed_created_addresses.ex b/apps/indexer/lib/indexer/temporary/failed_created_addresses.ex deleted file mode 100644 index a80cf657cd..0000000000 --- a/apps/indexer/lib/indexer/temporary/failed_created_addresses.ex +++ /dev/null @@ -1,132 +0,0 @@ -defmodule Indexer.Temporary.FailedCreatedAddresses do - @moduledoc """ - Temporary module to fix internal transactions and their created transactions if a parent transaction has failed. - """ - use GenServer - use Indexer.Fetcher - - require Logger - - import Ecto.Query - - alias Explorer.Chain.{Address, Data, InternalTransaction, Transaction} - alias Explorer.Repo - alias Indexer.Fetcher.ContractCode - alias Indexer.Temporary.FailedCreatedAddresses.TaskSupervisor - - @task_options [max_concurrency: 3, timeout: :infinity] - @query_timeout :infinity - - def start_link([json_rpc_named_arguments, gen_server_options]) do - GenServer.start_link(__MODULE__, json_rpc_named_arguments, gen_server_options) - end - - @impl GenServer - def init(json_rpc_named_arguments) do - schedule_work() - - {:ok, json_rpc_named_arguments} - end - - def schedule_work do - Process.send_after(self(), :run, 1_000) - end - - @impl GenServer - def handle_info(:run, json_rpc_named_arguments) do - run(json_rpc_named_arguments) - - {:noreply, json_rpc_named_arguments} - end - - def run(json_rpc_named_arguments) do - Logger.debug( - [ - "Started query to fetch internal transactions that need to be fixed" - ], - fetcher: :failed_created_addresses - ) - - data = %Data{bytes: ""} - - query = - from(t in Transaction, - left_join: it in InternalTransaction, - on: it.transaction_hash == t.hash, - left_join: address in Address, - on: address.hash == it.created_contract_address_hash, - where: t.status == ^0 and not is_nil(it.created_contract_address_hash) and address.contract_code != ^data, - distinct: t.hash - ) - - found_transactions = Repo.all(query, timeout: @query_timeout) - - Logger.debug( - [ - "Finished query to fetch internal transactions that need to be fixed. Number of records is #{ - Enum.count(found_transactions) - }" - ], - fetcher: :failed_created_addresses - ) - - TaskSupervisor - |> Task.Supervisor.async_stream_nolink( - found_transactions, - fn transaction -> fix_internal_transaction(transaction, json_rpc_named_arguments) end, - @task_options - ) - |> Enum.to_list() - end - - def fix_internal_transaction(transaction, json_rpc_named_arguments) do - # credo:disable-for-next-line - try do - Logger.debug( - [ - "Started fixing transaction #{to_string(transaction.hash)}" - ], - fetcher: :failed_created_addresses - ) - - transaction_with_internal_transactions = Repo.preload(transaction, [:internal_transactions]) - - transaction_with_internal_transactions.internal_transactions - |> Enum.filter(fn internal_transaction -> - internal_transaction.created_contract_address_hash - end) - |> Enum.each(fn internal_transaction -> - :ok = - internal_transaction - |> code_entry() - |> ContractCode.run(json_rpc_named_arguments) - end) - - Logger.debug( - [ - "Finished fixing transaction #{to_string(transaction.hash)}" - ], - fetcher: :failed_created_addresses - ) - rescue - e -> - Logger.debug( - [ - "Failed fixing transaction #{to_string(transaction.hash)} because of #{inspect(e)}" - ], - fetcher: :failed_created_addresses - ) - end - end - - def code_entry(%InternalTransaction{ - block_number: block_number, - created_contract_address_hash: %{bytes: created_contract_bytes} - }) do - [{block_number, created_contract_bytes, <<>>}] - end - - def transaction_entry(%Transaction{hash: %{bytes: bytes}, index: index, block_number: block_number}) do - [{block_number, bytes, index}] - end -end diff --git a/apps/indexer/test/indexer/temporary/addresses_without_code_test.exs b/apps/indexer/test/indexer/temporary/addresses_without_code_test.exs deleted file mode 100644 index 18efd3b557..0000000000 --- a/apps/indexer/test/indexer/temporary/addresses_without_code_test.exs +++ /dev/null @@ -1,389 +0,0 @@ -defmodule Indexer.Temporary.AddressesWithoutCodeTest do - use Explorer.DataCase, async: false - use EthereumJSONRPC.Case, async: false - - import Mox - - import Ecto.Query - - alias Explorer.Repo - alias Explorer.Chain.{Address, Transaction} - alias Indexer.Block.Fetcher - alias Indexer.Block.Realtime.Fetcher, as: RealtimeFetcher - alias Indexer.Fetcher.{CoinBalance, ContractCode, InternalTransaction, ReplacedTransaction, Token, TokenBalance} - alias Indexer.Temporary.AddressesWithoutCode.Supervisor - - @moduletag capture_log: true - - setup :set_mox_global - - setup :verify_on_exit! - - describe "run/1" do - setup %{json_rpc_named_arguments: json_rpc_named_arguments} do - CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - ReplacedTransaction.Supervisor.Case.start_supervised!() - - [name: Indexer.Block.Realtime.TaskSupervisor] - |> Task.Supervisor.child_spec() - |> ExUnit.Callbacks.start_supervised!() - - fetcher = %Fetcher{ - broadcast: false, - callback_module: RealtimeFetcher, - json_rpc_named_arguments: json_rpc_named_arguments - } - - {:ok, %{fetcher: fetcher}} - end - - @tag :no_parity - @tag :no_geth - test "refetches blocks setting created address and code", %{ - fetcher: %{json_rpc_named_arguments: json_rpc_named_arguments} = fetcher - } do - block = insert(:block, consensus: true) - - transaction = - :transaction - |> insert( - status: 0, - to_address: nil, - created_contract_address_hash: nil, - block: block, - block_number: block.number, - block_hash: block.hash, - cumulative_gas_used: 200, - gas_used: 100, - index: 0 - ) - - address = insert(:address, contract_code: nil) - - if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do - EthereumJSONRPC.Mox - |> expect(:json_rpc, fn [%{id: id, method: "eth_getBlockByNumber", params: [_block_quantity, true]}], - _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: %{ - "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "difficulty" => "0xfffffffffffffffffffffffffffffffe", - "extraData" => "0xd5830108048650617269747986312e32322e31826c69", - "gasLimit" => "0x69fe20", - "gasUsed" => "0xc512", - "hash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "logsBloom" => - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "number" => "0x25", - "parentHash" => "0xc37bbad7057945d1bf128c1ff009fb1ad632110bf6a000aac025a80f7766b66e", - "receiptsRoot" => "0xd300311aab7dcc98c05ac3f1893629b2c9082c189a0a0c76f4f63e292ac419d5", - "sealFields" => [ - "0x84120a71de", - "0xb841fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401" - ], - "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "signature" => - "fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401", - "size" => "0x2cf", - "stateRoot" => "0x2cd84079b0d0c267ed387e3895fd1c1dc21ff82717beb1132adac64276886e19", - "step" => "302674398", - "timestamp" => "0x5a343956", - "totalDifficulty" => "0x24ffffffffffffffffffffffffedf78dfd", - "transactions" => [ - %{ - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "chainId" => "0x4d", - "condition" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "creates" => to_string(address.hash), - "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "to" => nil, - "gas" => "0x47b760", - "gasPrice" => "0x174876e800", - "hash" => to_string(transaction.hash), - "input" => "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", - "nonce" => "0x4", - "publicKey" => - "0xe5d196ad4ceada719d9e592f7166d0c75700f6eab2e3c3de34ba751ea786527cb3f6eb96ad9fdfdb9989ff572df50f1c42ef800af9c5207a38b929aff969b5c9", - "r" => "0xa7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01", - "raw" => - "0xf88a0485174876e8008347b760948bf38d4764929064f2d4d3a56520a76ab3df415b80a410855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef81bea0a7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01a01f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f", - "s" => "0x1f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f", - "standardV" => "0x1", - "transactionIndex" => "0x0", - "v" => "0xbe", - "value" => "0x0" - } - ], - "transactionsRoot" => "0x68e314a05495f390f9cd0c36267159522e5450d2adf254a74567b452e767bf34", - "uncles" => [] - } - } - ]} - end) - |> expect(:json_rpc, fn [ - %{ - id: id, - method: "eth_getTransactionReceipt", - params: _ - } - ], - _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: %{ - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "contractAddress" => to_string(address.hash), - "cumulativeGasUsed" => "0xc512", - "gasUsed" => "0xc512", - "logs" => [ - %{ - "address" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", - "logIndex" => "0x0", - "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], - "transactionHash" => to_string(transaction.hash), - "transactionIndex" => "0x0", - "transactionLogIndex" => "0x0", - "type" => "mined" - } - ], - "logsBloom" => - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "root" => nil, - "status" => "0x1", - "transactionHash" => to_string(transaction.hash), - "transactionIndex" => "0x0" - } - } - ]} - end) - |> expect(:json_rpc, fn [%{id: id, method: "trace_block", params: _}], _options -> - {:ok, [%{id: id, result: []}]} - end) - |> expect(:json_rpc, fn [%{id: id, method: "trace_replayBlockTransactions", params: _}], _options -> - {:ok, [%{id: id, result: []}]} - end) - |> expect(:json_rpc, fn [ - %{ - id: 0, - jsonrpc: "2.0", - method: "eth_getBalance", - params: ["0x0000000000000000000000000000000000000003", "0x25"] - }, - %{ - id: 1, - jsonrpc: "2.0", - method: "eth_getBalance", - params: ["0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", "0x25"] - } - ], - _options -> - {:ok, [%{id: 0, jsonrpc: "2.0", result: "0x0"}, %{id: 1, jsonrpc: "2.0", result: "0x0"}]} - end) - end - - [fetcher, [name: AddressesWithoutCodeTest]] - |> Supervisor.child_spec() - |> ExUnit.Callbacks.start_supervised!() - - Process.sleep(5_000) - - updated_address = - from(a in Address, where: a.hash == ^address.hash, preload: :contracts_creation_transaction) |> Repo.one() - - assert updated_address.contracts_creation_transaction.hash == transaction.hash - - updated_transaction = - from(t in Transaction, where: t.hash == ^transaction.hash, preload: :created_contract_address) |> Repo.one() - - assert updated_transaction.created_contract_address.hash == address.hash - - assert updated_address.contract_code == updated_transaction.input - end - - @tag :no_parity - @tag :no_geth - test "doesn't set contract code if contract wasn't create", %{ - fetcher: %{json_rpc_named_arguments: json_rpc_named_arguments} = fetcher - } do - block = insert(:block, consensus: true) - - transaction = - :transaction - |> insert( - status: 0, - to_address: nil, - created_contract_address_hash: nil, - block: block, - block_number: block.number, - block_hash: block.hash, - cumulative_gas_used: 200, - gas_used: 100, - index: 0 - ) - - address = insert(:address, contract_code: nil) - - if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do - EthereumJSONRPC.Mox - |> expect(:json_rpc, fn [%{id: id, method: "eth_getBlockByNumber", params: [_block_quantity, true]}], - _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: %{ - "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "difficulty" => "0xfffffffffffffffffffffffffffffffe", - "extraData" => "0xd5830108048650617269747986312e32322e31826c69", - "gasLimit" => "0x69fe20", - "gasUsed" => "0xc512", - "hash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "logsBloom" => - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "number" => "0x25", - "parentHash" => "0xc37bbad7057945d1bf128c1ff009fb1ad632110bf6a000aac025a80f7766b66e", - "receiptsRoot" => "0xd300311aab7dcc98c05ac3f1893629b2c9082c189a0a0c76f4f63e292ac419d5", - "sealFields" => [ - "0x84120a71de", - "0xb841fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401" - ], - "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "signature" => - "fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401", - "size" => "0x2cf", - "stateRoot" => "0x2cd84079b0d0c267ed387e3895fd1c1dc21ff82717beb1132adac64276886e19", - "step" => "302674398", - "timestamp" => "0x5a343956", - "totalDifficulty" => "0x24ffffffffffffffffffffffffedf78dfd", - "transactions" => [ - %{ - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "chainId" => "0x4d", - "condition" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "to" => nil, - "gas" => "0x47b760", - "gasPrice" => "0x174876e800", - "hash" => to_string(transaction.hash), - "input" => "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", - "nonce" => "0x4", - "publicKey" => - "0xe5d196ad4ceada719d9e592f7166d0c75700f6eab2e3c3de34ba751ea786527cb3f6eb96ad9fdfdb9989ff572df50f1c42ef800af9c5207a38b929aff969b5c9", - "r" => "0xa7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01", - "raw" => - "0xf88a0485174876e8008347b760948bf38d4764929064f2d4d3a56520a76ab3df415b80a410855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef81bea0a7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01a01f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f", - "s" => "0x1f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f", - "standardV" => "0x1", - "transactionIndex" => "0x0", - "v" => "0xbe", - "value" => "0x0" - } - ], - "transactionsRoot" => "0x68e314a05495f390f9cd0c36267159522e5450d2adf254a74567b452e767bf34", - "uncles" => [] - } - } - ]} - end) - |> expect(:json_rpc, fn [ - %{ - id: id, - method: "eth_getTransactionReceipt", - params: _ - } - ], - _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: %{ - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "contractAddress" => nil, - "cumulativeGasUsed" => "0xc512", - "gasUsed" => "0xc512", - "logs" => [ - %{ - "address" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", - "logIndex" => "0x0", - "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], - "transactionHash" => to_string(transaction.hash), - "transactionIndex" => "0x0", - "transactionLogIndex" => "0x0", - "type" => "mined" - } - ], - "logsBloom" => - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "root" => nil, - "status" => "0x1", - "transactionHash" => to_string(transaction.hash), - "transactionIndex" => "0x0" - } - } - ]} - end) - |> expect(:json_rpc, fn [%{id: id, method: "trace_block", params: _}], _options -> - {:ok, [%{id: id, result: []}]} - end) - |> expect(:json_rpc, fn [%{id: id, method: "trace_replayBlockTransactions", params: _}], _options -> - {:ok, [%{id: id, result: []}]} - end) - |> expect(:json_rpc, fn [ - %{ - id: 1, - jsonrpc: "2.0", - method: "eth_getBalance", - params: ["0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca", "0x25"] - } - ], - _options -> - {:ok, [%{id: 1, jsonrpc: "2.0", result: "0x0"}]} - end) - end - - [fetcher, [name: AddressesWithoutCodeTest1]] - |> Supervisor.child_spec() - |> ExUnit.Callbacks.start_supervised!() - - Process.sleep(2_000) - - updated_address = - from(a in Address, where: a.hash == ^address.hash, preload: :contracts_creation_transaction) |> Repo.one() - - assert is_nil(updated_address.contracts_creation_transaction) - - updated_transaction = - from(t in Transaction, where: t.hash == ^transaction.hash, preload: :created_contract_address) |> Repo.one() - - assert is_nil(updated_transaction.created_contract_address) - - assert is_nil(updated_address.contract_code) - end - end -end diff --git a/apps/indexer/test/indexer/temporary/failed_created_addresses_test.exs b/apps/indexer/test/indexer/temporary/failed_created_addresses_test.exs deleted file mode 100644 index ef03376161..0000000000 --- a/apps/indexer/test/indexer/temporary/failed_created_addresses_test.exs +++ /dev/null @@ -1,78 +0,0 @@ -defmodule Indexer.Temporary.FailedCreatedAddressesTest do - use Explorer.DataCase, async: false - use EthereumJSONRPC.Case, async: false - - import Mox - - import Ecto.Query - - alias Explorer.Repo - alias Explorer.Chain.Address - alias Indexer.Fetcher.CoinBalance - alias Indexer.Temporary.FailedCreatedAddresses.Supervisor - - @moduletag capture_log: true - - setup :set_mox_global - - setup :verify_on_exit! - - describe "run/1" do - @tag :no_parity - @tag :no_geth - test "updates failed replaced transactions", %{json_rpc_named_arguments: json_rpc_named_arguments} do - CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) - - block = insert(:block) - - transaction = - :transaction - |> insert( - status: 0, - error: "Reverted", - internal_transactions_indexed_at: DateTime.utc_now(), - block: block, - block_number: block.number, - cumulative_gas_used: 200, - gas_used: 100, - index: 0 - ) - - address = insert(:address, contract_code: "0x0102030405") - - insert(:internal_transaction, - block_number: transaction.block_number, - transaction: transaction, - index: 0, - created_contract_address_hash: address.hash - ) - - if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do - EthereumJSONRPC.Mox - |> expect(:json_rpc, fn _json, _options -> - {:ok, [%{id: 0, jsonrpc: "2.0", result: "0x"}]} - end) - |> expect(:json_rpc, fn [%{id: id, method: "eth_getBalance", params: [_address, _block_quantity]}], _options -> - {:ok, [%{id: id, result: "0x0"}]} - end) - end - - params = [json_rpc_named_arguments, [name: TestFailedCreatedAddresses]] - - params - |> Supervisor.child_spec() - |> ExUnit.Callbacks.start_supervised!() - - Process.sleep(3_000) - - fetched_address = - Repo.one( - from(a in Address, - where: a.hash == ^address.hash - ) - ) - - assert fetched_address.contract_code == %Explorer.Chain.Data{bytes: ""} - end - end -end From 88a2a528f7c3711b5092294060301416da7cbaab Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 6 May 2019 10:30:34 +0300 Subject: [PATCH 02/11] fix build --- apps/indexer/lib/indexer/supervisor.ex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/indexer/lib/indexer/supervisor.ex b/apps/indexer/lib/indexer/supervisor.ex index 4e04b53092..21dc3637ec 100644 --- a/apps/indexer/lib/indexer/supervisor.ex +++ b/apps/indexer/lib/indexer/supervisor.ex @@ -78,12 +78,6 @@ defmodule Indexer.Supervisor do |> Map.drop(~w(block_interval blocks_concurrency memory_monitor subscribe_named_arguments realtime_overrides)a) |> Block.Fetcher.new() - fixing_realtime_fetcher = %Block.Fetcher{ - broadcast: false, - callback_module: Realtime.Fetcher, - json_rpc_named_arguments: json_rpc_named_arguments - } - realtime_block_fetcher = named_arguments |> Map.drop(~w(block_interval blocks_concurrency memory_monitor subscribe_named_arguments realtime_overrides)a) From baecd9462d9393a2b54ef181928f323a880fcfe6 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 6 May 2019 10:36:31 +0300 Subject: [PATCH 03/11] add CHANGELOG entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7901172443..40aa891851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - [#1815](https://github.com/poanetwork/blockscout/pull/1815) - able to search without prefix "0x" - [#1813](https://github.com/poanetwork/blockscout/pull/1813) - add total blocks counter to the main page - [#1806](https://github.com/poanetwork/blockscout/pull/1806) - verify contracts with a post request -- [#1857](https://github.com/poanetwork/blockscout/pull/1857) - Re-implement Geth JS internal transaction tracer in Elixir +- [#1857](https://github.com/poanetwork/blockscout/pull/1857) - Re-implement Geth JS internal transaction tracer in Elixir - [#1859](https://github.com/poanetwork/blockscout/pull/1859) - feat: show raw transaction traces ### Fixes @@ -23,6 +23,7 @@ - [#1814](https://github.com/poanetwork/blockscout/pull/1814) - Clear build artefacts script - [#1837](https://github.com/poanetwork/blockscout/pull/1837) - Add -f flag to clear_build.sh script delete static folder +- [#1892](https://github.com/poanetwork/blockscout/pull/1892) - Remove temporary worker modules ## 1.3.10-beta From ab758d008aa1709d662f107de1bc7e6c220dd508 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 7 May 2019 11:26:09 +0300 Subject: [PATCH 04/11] check if construct has arguments --- .../lib/explorer/smart_contract/verifier.ex | 6 +- .../solidity/code_compiler_test.exs | 95 +++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 0fc9f6b21b..4b521fba35 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -74,7 +74,7 @@ defmodule Explorer.SmartContract.Verifier do generated_bytecode != blockchain_bytecode_without_whisper -> {:error, :generated_bytecode} - !ConstructorArguments.verify(address_hash, arguments_data) -> + has_constructor_with_params?(abi) && !ConstructorArguments.verify(address_hash, arguments_data) -> {:error, :constructor_arguments} true -> @@ -111,4 +111,8 @@ defmodule Explorer.SmartContract.Verifier do prev_version end end + + defp has_constructor_with_params?(abi) do + Enum.any?(abi, fn el -> el["type"] == "constructor" && el["inputs"] != [] end) + end end diff --git a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs index 79bbb62f70..57f15577ac 100644 --- a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs +++ b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs @@ -173,6 +173,101 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do assert {:error, :compilation} = response end + + test "returns constructor in abi" do + code = """ + pragma solidity ^0.4.22; + + contract OwnedToken { + // TokenCreator is a contract type that is defined below. + // It is fine to reference it as long as it is not used + // to create a new contract. + TokenCreator creator; + address owner; + bytes32 name; + + // This is the constructor which registers the + // creator and the assigned name. + constructor(bytes32 _name) public { + // State variables are accessed via their name + // and not via e.g. this.owner. This also applies + // to functions and especially in the constructors, + // you can only call them like that ("internally"), + // because the contract itself does not exist yet. + owner = msg.sender; + // We do an explicit type conversion from `address` + // to `TokenCreator` and assume that the type of + // the calling contract is TokenCreator, there is + // no real way to check that. + creator = TokenCreator(msg.sender); + name = _name; + } + + function changeName(bytes32 newName) public { + // Only the creator can alter the name -- + // the comparison is possible since contracts + // are implicitly convertible to addresses. + if (msg.sender == address(creator)) + name = newName; + } + + function transfer(address newOwner) public { + // Only the current owner can transfer the token. + if (msg.sender != owner) return; + // We also want to ask the creator if the transfer + // is fine. Note that this calls a function of the + // contract defined below. If the call fails (e.g. + // due to out-of-gas), the execution here stops + // immediately. + if (creator.isTokenTransferOK(owner, newOwner)) + owner = newOwner; + } + } + + contract TokenCreator { + function createToken(bytes32 name) + public + returns (OwnedToken tokenAddress) + { + // Create a new Token contract and return its address. + // From the JavaScript side, the return type is simply + // `address`, as this is the closest type available in + // the ABI. + return new OwnedToken(name); + } + + function changeName(OwnedToken tokenAddress, bytes32 name) public { + // Again, the external type of `tokenAddress` is + // simply `address`. + tokenAddress.changeName(name); + } + + function isTokenTransferOK(address currentOwner, address newOwner) + public + view + returns (bool ok) + { + // Check some arbitrary condition. + address tokenAddress = msg.sender; + return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); + } + } + """ + + name = "OwnedToken" + compiler_version = "v0.4.22+commit.4cb486ee" + + {:ok, %{"abi" => abi}} = + CodeCompiler.run( + name: name, + compiler_version: compiler_version, + code: code, + evm_version: "byzantium", + optimize: true + ) + + assert Enum.any?(abi, fn el -> el["type"] == "constructor" end) + end end describe "get_contract_info/1" do From e8bc0e6b6bcadb16ffacc5753401cf3755d50209 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 7 May 2019 11:41:51 +0300 Subject: [PATCH 05/11] remove expired test --- .../explorer/smart_contract/verifier_test.exs | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 631c15695e..1e8301a90c 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -117,31 +117,6 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end - test "returns error when constructor arguments do not match", %{ - contract_code_info: contract_code_info - } do - contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - - constructor_arguments = "0102030405" - - params = %{ - "contract_source_code" => contract_code_info.source_code, - "compiler_version" => contract_code_info.version, - "name" => contract_code_info.name, - "optimization" => contract_code_info.optimized, - "constructor_arguments" => constructor_arguments - } - - :transaction - |> insert( - created_contract_address_hash: contract_address.hash, - input: Verifier.extract_bytecode(contract_code_info.bytecode) <> "010203" - ) - |> with_block() - - assert {:error, :constructor_arguments} = Verifier.evaluate_authenticity(contract_address.hash, params) - end - test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) From 7acf983c9bf6020f723c165e9faa368961a3cac2 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 7 May 2019 11:44:40 +0300 Subject: [PATCH 06/11] add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1460a1af7d..a546f01a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - [#1822](https://github.com/poanetwork/blockscout/pull/1822) - Fix style breaks in decompiled contract code view - [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete - [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance +- [#1898](https://github.com/poanetwork/blockscout/pull/1898) - check if the constructor has arguments before verifying constructor arguments ### Chore From be1623b07eef672132e5e949e07ea4ee71348a43 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 7 May 2019 14:56:43 +0300 Subject: [PATCH 07/11] fix System.get_env("BLOCK_COUNT_CACHE_TTL") type --- apps/explorer/config/config.exs | 3 ++- apps/explorer/lib/explorer/chain/block_count_cache.ex | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index ace69884ea..f40e10371b 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -82,7 +82,8 @@ config :spandex_ecto, SpandexEcto.EctoLogger, tracer: Explorer.Tracer, otp_app: :explorer -config :explorer, Explorer.Chain.BlockCountCache, ttl: System.get_env("BLOCK_COUNT_CACHE_TTL") +config :explorer, Explorer.Chain.BlockCountCache, + ttl: System.get_env("BLOCK_COUNT_CACHE_TTL") && String.to_integer(System.get_env("BLOCK_COUNT_CACHE_TTL")) # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/apps/explorer/lib/explorer/chain/block_count_cache.ex b/apps/explorer/lib/explorer/chain/block_count_cache.ex index 7c900bfedd..84f016dd44 100644 --- a/apps/explorer/lib/explorer/chain/block_count_cache.ex +++ b/apps/explorer/lib/explorer/chain/block_count_cache.ex @@ -6,8 +6,8 @@ defmodule Explorer.Chain.BlockCountCache do alias Explorer.Chain @tab :block_count_cache - # 1 minutes - @cache_period 1_000 * 60 + # 10 minutes + @cache_period 1_000 * 60 * 10 @key "count" @opts_key "opts" From b72cdaecdfbab39aa20b9c570e9d9c47f81845eb Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 7 May 2019 14:59:08 +0300 Subject: [PATCH 08/11] add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef0fe2319..2bb5799000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [#1885](https://github.com/poanetwork/blockscout/pull/1885) - highlight reserved words in decompiled code - [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete - [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance +- [#1904](https://github.com/poanetwork/blockscout/pull/1904) - fix `BLOCK_COUNT_CACHE_TTL` env var type ### Chore From e08b9f7ecc2cff2d6b9f97d6f8e4ba327f8232ab Mon Sep 17 00:00:00 2001 From: zachdaniel Date: Wed, 1 May 2019 10:33:09 -0400 Subject: [PATCH 09/11] fix: resolve false positive constructor arguments --- CHANGELOG.md | 1 + .../smart_contract/solidity/code_compiler.ex | 6 ++++ .../lib/explorer/smart_contract/verifier.ex | 31 ++++++++++++++----- .../explorer/smart_contract/verifier_test.exs | 18 ++++++++++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4b8db4d5..ca08e35fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - [#1885](https://github.com/poanetwork/blockscout/pull/1885) - highlight reserved words in decompiled code - [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete - [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance +- [#1875](https://github.com/poanetwork/blockscout/pull/1875) - fix: resolve false positive constructor arguments ### Chore diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex index 72c5bae186..3ded8ba9f1 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex @@ -63,6 +63,7 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do } } """ + @spec run(Keyword.t()) :: {:ok, map} | {:error, :compilation | :name} def run(params) do name = Keyword.fetch!(params, :name) compiler_version = Keyword.fetch!(params, :compiler_version) @@ -108,9 +109,14 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do {:error, %Jason.DecodeError{}} -> {:error, :compilation} + {:error, reason} when reason in [:name, :compilation] -> + {:error, reason} + error -> parse_error(error) end + else + {:error, :compilation} end end diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 0fc9f6b21b..746ba610aa 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -86,17 +86,32 @@ defmodule Explorer.SmartContract.Verifier do In order to discover the bytecode we need to remove the `swarm source` from the hash. - `64` characters to the left of `0029` are the `swarm source`. The rest on - the left is the `bytecode` to be validated. + For more information on the swarm hash, check out: + https://solidity.readthedocs.io/en/v0.5.3/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode """ + def extract_bytecode("0x" <> code) do + "0x" <> extract_bytecode(code) + end + def extract_bytecode(code) do - {bytecode, _swarm_source} = - code - |> String.split("0029") - |> List.first() - |> String.split_at(-64) + do_extract_bytecode([], String.downcase(code)) + end - bytecode + defp do_extract_bytecode(extracted, remaining) do + case remaining do + <<>> -> + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + + "a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> _constructor_arguments -> + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + + <> <> rest -> + do_extract_bytecode([next | extracted], rest) + end end def next_evm_version(current_evm_version) do diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 631c15695e..6786e559df 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -181,7 +181,7 @@ defmodule Explorer.SmartContract.VerifierTest do swarm_source = "3c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b" bytecode = - "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820" + "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" assert bytecode == Verifier.extract_bytecode(code) assert bytecode != code @@ -189,5 +189,21 @@ defmodule Explorer.SmartContract.VerifierTest do assert String.contains?(bytecode, "0029") == false assert String.contains?(bytecode, swarm_source) == false end + + test "extracts everything to the left of the swarm hash" do + code = + "0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058203c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b0029" + + swarm_source = "3c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b" + + bytecode = + "0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" + + assert bytecode == Verifier.extract_bytecode(code) + assert bytecode != code + assert String.contains?(code, bytecode) == true + assert String.contains?(bytecode, "0029") == true + assert String.contains?(bytecode, swarm_source) == false + end end end From c3a5218ff5579aa97863ea2d58a632e64085063a Mon Sep 17 00:00:00 2001 From: zachdaniel Date: Tue, 7 May 2019 12:41:49 -0400 Subject: [PATCH 10/11] fix: split constructor args for verification --- .../smart_contract/solidity/code_compiler.ex | 18 ++++++++++--- .../verifier/constructor_arguments.ex | 25 ++++++++++--------- apps/explorer/priv/compile_solc.js | 4 +-- .../verifier/constructor_arguments_test.exs | 14 ++++++----- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex index 3ded8ba9f1..656f1b9734 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex @@ -5,6 +5,8 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do alias Explorer.SmartContract.SolcDownloader + require Logger + @new_contract_name "New.sol" @allowed_evm_versions ["homestead", "tangerineWhistle", "spuriousDragon", "byzantium", "constantinople", "petersburg"] @@ -101,7 +103,8 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do ] ) - with {:ok, contracts} <- Jason.decode(response), + with {:ok, decoded} <- Jason.decode(response), + {:ok, contracts} <- get_contracts(decoded), %{"abi" => abi, "evm" => %{"deployedBytecode" => %{"object" => bytecode}}} <- get_contract_info(contracts, name) do {:ok, %{"abi" => abi, "bytecode" => bytecode, "name" => name}} @@ -113,7 +116,9 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do {:error, reason} error -> - parse_error(error) + error = parse_error(error) + Logger.warn(["There was an error compiling a provided contract: ", inspect(error)]) + {:error, :compilation} end else {:error, :compilation} @@ -139,10 +144,15 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do end end - def parse_error(%{"error" => error}), do: {:error, [error]} - def parse_error(%{"errors" => errors}), do: {:error, errors} + def parse_error({:error, %{"error" => error}}), do: {:error, [error]} + def parse_error({:error, %{"errors" => errors}}), do: {:error, errors} def parse_error({:error, _} = error), do: error + # Older solc-bin versions don't use filename as contract key + defp get_contracts(%{"contracts" => %{"New.sol" => contracts}}), do: {:ok, contracts} + defp get_contracts(%{"contracts" => %{"" => contracts}}), do: {:ok, contracts} + defp get_contracts(response), do: {:error, response} + defp optimize_value(false), do: "0" defp optimize_value("false"), do: "0" diff --git a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex index b60bd01927..aa32d85bb6 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex @@ -7,20 +7,21 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do def verify(address_hash, arguments_data) do arguments_data = String.replace(arguments_data, "0x", "") - creation_input_data = Chain.contract_creation_input_data(address_hash) - data_with_swarm = - creation_input_data - |> String.split("0029") - |> List.first() - |> Kernel.<>("0029") + address_hash + |> Chain.contract_creation_input_data() + |> String.replace("0x", "") + |> extract_constructor_arguments() + |> Kernel.==(arguments_data) + end + + defp extract_constructor_arguments(<<>>), do: "" - expected_arguments_data = - creation_input_data - |> String.split(data_with_swarm) - |> List.last() - |> String.replace("0x", "") + defp extract_constructor_arguments("a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> constructor_arguments) do + constructor_arguments + end - expected_arguments_data == arguments_data + defp extract_constructor_arguments(<<_::binary-size(2)>> <> rest) do + extract_constructor_arguments(rest) end end diff --git a/apps/explorer/priv/compile_solc.js b/apps/explorer/priv/compile_solc.js index 5aaf3f54d7..eea727802e 100755 --- a/apps/explorer/priv/compile_solc.js +++ b/apps/explorer/priv/compile_solc.js @@ -39,6 +39,4 @@ const input = { const output = JSON.parse(solc.compile(JSON.stringify(input))) -/** Older solc-bin versions don't use filename as contract key */ -const response = output.contracts[newContractName] || output.contracts[''] -console.log(JSON.stringify(response)); +console.log(JSON.stringify(output)); diff --git a/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs b/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs index 9fe219719d..a5e019c86f 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier/constructor_arguments_test.exs @@ -7,17 +7,19 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArgumentsTest do alias Explorer.SmartContract.Verifier.ConstructorArguments test "veriies constructor constructor arguments with whisper data" do - constructor_arguments = "0x0405" + constructor_arguments = Base.encode16(:crypto.strong_rand_bytes(64), case: :lower) address = insert(:address) - input = %Data{ - bytes: - <<1, 2, 3, 93, 148, 60, 87, 91, 232, 162, 174, 226, 187, 119, 55, 167, 101, 253, 210, 198, 228, 155, 116, 205, - 44, 146, 171, 15, 168, 228, 40, 45, 26, 117, 174, 0, 41, 4, 5>> + input = + "a165627a7a72305820" <> + Base.encode16(:crypto.strong_rand_bytes(32), case: :lower) <> "0029" <> constructor_arguments + + input_data = %Data{ + bytes: Base.decode16!(input, case: :lower) } :transaction - |> insert(created_contract_address_hash: address.hash, input: input) + |> insert(created_contract_address_hash: address.hash, input: input_data) |> with_block() assert ConstructorArguments.verify(address.hash, constructor_arguments) From 7cb07f3610f9b4a38c972ab7580f4d337a122a7a Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 8 May 2019 11:49:44 +0300 Subject: [PATCH 11/11] remove workers from indexer readme --- apps/indexer/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/indexer/README.md b/apps/indexer/README.md index d0844c57d6..34fb6e6ef3 100644 --- a/apps/indexer/README.md +++ b/apps/indexer/README.md @@ -91,8 +91,6 @@ These workers are created for fetching information, which previously wasn't fetc After all deployed instances get all needed data, these fetchers should be deprecated and removed. - `uncataloged_token_transfers`: extracts token transfers from logs, which previously weren't parsed due to unknown format -- `addresses_without_codes`: forces complete refetch of blocks, which have created contract addresses without contract code -- `failed_created_addresses`: forces refetch of contract code for failed transactions, which previously got incorrectly overwritten - `uncles_without_index`: adds previously unfetched `index` field for unfetched blocks in `block_second_degree_relations` ## Memory Usage @@ -156,4 +154,3 @@ mix test --exclude no_geth |:----------|:--------------------------------------------------| | HTTP | `https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY` | | WebSocket | `wss://mainnet.infura.io/ws/8lTvJTKmHPCHazkneJsY` | -