Show compilation error at conntract verification

pull/3199/head
Victor Baranov 4 years ago
parent 880e17289e
commit 0a0bd31abc
  1. 1
      .dialyzer-ignore
  2. 1
      CHANGELOG.md
  3. 35
      apps/explorer/lib/explorer/chain/smart_contract.ex
  4. 10
      apps/explorer/lib/explorer/smart_contract/publisher.ex
  5. 4
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  6. 10
      apps/explorer/lib/explorer/smart_contract/verifier.ex

@ -6,6 +6,7 @@ apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex:400: Function timestamp_to_datetim
lib/explorer/repo/prometheus_logger.ex:8 lib/explorer/repo/prometheus_logger.ex:8
lib/block_scout_web/views/layout_view.ex:175 lib/block_scout_web/views/layout_view.ex:175
lib/explorer/smart_contract/publisher_worker.ex:6 lib/explorer/smart_contract/publisher_worker.ex:6
lib/explorer/smart_contract/verifier.ex:82
apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: Function microseconds_time/1 has no local return apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: Function microseconds_time/1 has no local return
apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: The call 'Elixir.System':convert_time_unit(__@1::any(),'native','microseconds') breaks the contract (integer(),time_unit() | 'native',time_unit() | 'native') -> integer() apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: The call 'Elixir.System':convert_time_unit(__@1::any(),'native','microseconds') breaks the contract (integer(),time_unit() | 'native',time_unit() | 'native') -> integer()
lib/block_scout_web/views/layout_view.ex:172: The call 'Elixir.Poison.Parser':'parse!'(any(),#{'keys':='atoms!'}) will never return since the success typing is (binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),[{atom(),_}]) -> 'false' | 'nil' | 'true' | binary() | ['false' | 'nil' | 'true' | binary() | [any()] | number() | map()] | number() | map() and the contract is (iodata(),'Elixir.Keyword':t()) -> t() lib/block_scout_web/views/layout_view.ex:172: The call 'Elixir.Poison.Parser':'parse!'(any(),#{'keys':='atoms!'}) will never return since the success typing is (binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),[{atom(),_}]) -> 'false' | 'nil' | 'true' | binary() | ['false' | 'nil' | 'true' | binary() | [any()] | number() | map()] | number() | map() and the contract is (iodata(),'Elixir.Keyword':t()) -> t()

@ -1,6 +1,7 @@
## Current ## Current
### Features ### Features
- [#3199](https://github.com/poanetwork/blockscout/pull/3199) - Show compilation error at contract verification
- [#3193](https://github.com/poanetwork/blockscout/pull/3193) - Raw trace copy button - [#3193](https://github.com/poanetwork/blockscout/pull/3193) - Raw trace copy button
- [#3184](https://github.com/poanetwork/blockscout/pull/3184) - Apps navbar menu item - [#3184](https://github.com/poanetwork/blockscout/pull/3184) - Apps navbar menu item
- [#3145](https://github.com/poanetwork/blockscout/pull/3145) - Pending txs per address API endpoint - [#3145](https://github.com/poanetwork/blockscout/pull/3145) - Pending txs per address API endpoint

@ -255,20 +255,26 @@ defmodule Explorer.Chain.SmartContract do
|> prepare_changes(&upsert_contract_methods/1) |> prepare_changes(&upsert_contract_methods/1)
end end
def invalid_contract_changeset(%__MODULE__{} = smart_contract, attrs, error) do def invalid_contract_changeset(%__MODULE__{} = smart_contract, attrs, error, error_message) do
smart_contract validated =
|> cast(attrs, [ smart_contract
:name, |> cast(attrs, [
:compiler_version, :name,
:optimization, :compiler_version,
:contract_source_code, :optimization,
:address_hash, :contract_source_code,
:evm_version, :address_hash,
:optimization_runs, :evm_version,
:constructor_arguments :optimization_runs,
]) :constructor_arguments
|> validate_required([:name, :compiler_version, :optimization, :address_hash]) ])
|> add_error(:contract_source_code, error_message(error)) |> validate_required([:name, :compiler_version, :optimization, :address_hash])
if error_message do
add_error(validated, :contract_source_code, error_message(error, error_message))
else
add_error(validated, :contract_source_code, error_message(error))
end
end end
def add_submitted_comment(code, inserted_at) when is_binary(code) do def add_submitted_comment(code, inserted_at) when is_binary(code) do
@ -331,4 +337,5 @@ defmodule Explorer.Chain.SmartContract do
defp error_message(:constructor_arguments), do: "Constructor arguments do not match, please try again." defp error_message(:constructor_arguments), do: "Constructor arguments do not match, please try again."
defp error_message(:name), do: "Wrong contract name, please try again." defp error_message(:name), do: "Wrong contract name, please try again."
defp error_message(_), do: "There was an error validating your contract, please try again." defp error_message(_), do: "There was an error validating your contract, please try again."
defp error_message(:compilation, error_message), do: "There was an error compiling your contract: #{error_message}"
end end

@ -37,7 +37,10 @@ defmodule Explorer.SmartContract.Publisher do
publish_smart_contract(address_hash, params_with_external_libaries, abi) publish_smart_contract(address_hash, params_with_external_libaries, abi)
{:error, error} -> {:error, error} ->
{:error, unverified_smart_contract(address_hash, params_with_external_libaries, error)} {:error, unverified_smart_contract(address_hash, params_with_external_libaries, error, nil)}
{:error, error, error_message} ->
{:error, unverified_smart_contract(address_hash, params_with_external_libaries, error, error_message)}
end end
end end
@ -47,14 +50,15 @@ defmodule Explorer.SmartContract.Publisher do
Chain.create_smart_contract(attrs, attrs.external_libraries) Chain.create_smart_contract(attrs, attrs.external_libraries)
end end
defp unverified_smart_contract(address_hash, params, error) do defp unverified_smart_contract(address_hash, params, error, error_message) do
attrs = attributes(address_hash, params) attrs = attributes(address_hash, params)
changeset = changeset =
SmartContract.invalid_contract_changeset( SmartContract.invalid_contract_changeset(
%SmartContract{address_hash: address_hash}, %SmartContract{address_hash: address_hash},
attrs, attrs,
error error,
error_message
) )
%{changeset | action: :insert} %{changeset | action: :insert}

@ -116,7 +116,9 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
error -> error ->
error = parse_error(error) error = parse_error(error)
Logger.warn(["There was an error compiling a provided contract: ", inspect(error)]) Logger.warn(["There was an error compiling a provided contract: ", inspect(error)])
{:error, :compilation} {:error, [first_error | _]} = error
%{"message" => error_message} = first_error
{:error, :compilation, error_message}
end end
else else
{:error, :compilation} {:error, :compilation}

@ -28,7 +28,11 @@ defmodule Explorer.SmartContract.Verifier do
latest_evm_version = List.last(CodeCompiler.allowed_evm_versions()) latest_evm_version = List.last(CodeCompiler.allowed_evm_versions())
evm_version = Map.get(params, "evm_version", latest_evm_version) evm_version = Map.get(params, "evm_version", latest_evm_version)
Enum.reduce([evm_version | previous_evm_versions(evm_version)], false, fn version, acc -> all_versions = [evm_version | previous_evm_versions(evm_version)]
all_versions_extra = all_versions ++ [evm_version]
Enum.reduce(all_versions_extra, false, fn version, acc ->
case acc do case acc do
{:ok, _} = result -> {:ok, _} = result ->
result result
@ -75,6 +79,10 @@ defmodule Explorer.SmartContract.Verifier do
defp compare_bytecodes({:error, :name}, _, _, _, _, _), do: {:error, :name} defp compare_bytecodes({:error, :name}, _, _, _, _, _), do: {:error, :name}
defp compare_bytecodes({:error, _}, _, _, _, _, _), do: {:error, :compilation} defp compare_bytecodes({:error, _}, _, _, _, _, _), do: {:error, :compilation}
defp compare_bytecodes({:error, _, error_message}, _, _, _, _, _) do
{:error, :compilation, error_message}
end
# credo:disable-for-next-line /Complexity/ # credo:disable-for-next-line /Complexity/
defp compare_bytecodes( defp compare_bytecodes(
{:ok, %{"abi" => abi, "bytecode" => bytecode}}, {:ok, %{"abi" => abi, "bytecode" => bytecode}},

Loading…
Cancel
Save