diff --git a/.dialyzer-ignore b/.dialyzer-ignore index 527272ec2d..79554ff44f 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -6,6 +6,7 @@ apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex:400: Function timestamp_to_datetim lib/explorer/repo/prometheus_logger.ex:8 lib/block_scout_web/views/layout_view.ex:175 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: 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() diff --git a/CHANGELOG.md b/CHANGELOG.md index 35a3e103f0..016b8234a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### 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 - [#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 diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 9d4c03134a..72c2d78b2b 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -255,20 +255,26 @@ defmodule Explorer.Chain.SmartContract do |> prepare_changes(&upsert_contract_methods/1) end - def invalid_contract_changeset(%__MODULE__{} = smart_contract, attrs, error) do - smart_contract - |> cast(attrs, [ - :name, - :compiler_version, - :optimization, - :contract_source_code, - :address_hash, - :evm_version, - :optimization_runs, - :constructor_arguments - ]) - |> validate_required([:name, :compiler_version, :optimization, :address_hash]) - |> add_error(:contract_source_code, error_message(error)) + def invalid_contract_changeset(%__MODULE__{} = smart_contract, attrs, error, error_message) do + validated = + smart_contract + |> cast(attrs, [ + :name, + :compiler_version, + :optimization, + :contract_source_code, + :address_hash, + :evm_version, + :optimization_runs, + :constructor_arguments + ]) + |> 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 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(: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(:compilation, error_message), do: "There was an error compiling your contract: #{error_message}" end diff --git a/apps/explorer/lib/explorer/smart_contract/publisher.ex b/apps/explorer/lib/explorer/smart_contract/publisher.ex index 28769d2604..24c51b2d24 100644 --- a/apps/explorer/lib/explorer/smart_contract/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/publisher.ex @@ -37,7 +37,10 @@ defmodule Explorer.SmartContract.Publisher do publish_smart_contract(address_hash, params_with_external_libaries, abi) {: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 @@ -47,14 +50,15 @@ defmodule Explorer.SmartContract.Publisher do Chain.create_smart_contract(attrs, attrs.external_libraries) 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) changeset = SmartContract.invalid_contract_changeset( %SmartContract{address_hash: address_hash}, attrs, - error + error, + error_message ) %{changeset | action: :insert} 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 3b83cafed6..4e72e8a5de 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex @@ -116,7 +116,9 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do error -> error = parse_error(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 else {:error, :compilation} diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 439f8f9757..ecb32fd588 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -28,7 +28,11 @@ defmodule Explorer.SmartContract.Verifier do latest_evm_version = List.last(CodeCompiler.allowed_evm_versions()) 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 {:ok, _} = result -> result @@ -75,6 +79,10 @@ defmodule Explorer.SmartContract.Verifier do defp compare_bytecodes({:error, :name}, _, _, _, _, _), do: {:error, :name} 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/ defp compare_bytecodes( {:ok, %{"abi" => abi, "bytecode" => bytecode}},