diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 1e348bfd12..ae2dae5cbe 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -28,7 +28,25 @@ defmodule Explorer.SmartContract.Verifier do solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization, evm_version, external_libraries) - compare_bytecodes(solc_output, address_hash, constructor_arguments) + case compare_bytecodes(solc_output, address_hash, constructor_arguments) do + {:error, :generated_bytecode} -> + next_evm_version = next_evm_version(evm_version) + + second_solc_output = + CodeCompiler.run( + name, + compiler_version, + contract_source_code, + optimization, + next_evm_version, + external_libraries + ) + + compare_bytecodes(second_solc_output, address_hash, constructor_arguments) + + result -> + result + end end defp compare_bytecodes({:error, :name}, _, _), do: {:error, :name} @@ -71,4 +89,17 @@ defmodule Explorer.SmartContract.Verifier do bytecode end + + def next_evm_version(current_evm_version) do + [prev_version, last_version] = + CodeCompiler.allowed_evm_versions() + |> Enum.reverse() + |> Enum.take(2) + + if current_evm_version != last_version do + last_version + else + prev_version + end + end end diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 92c23226f8..631c15695e 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -82,6 +82,41 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end + test "tries to compile with the latest evm version if wrong evm version was provided" do + bytecode = + "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063256fec88146100545780633fa4f245146100a9578063812600df146100d2575b600080fd5b341561005f57600080fd5b6100676100f5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100b457600080fd5b6100bc61011b565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b6100f36004808035906020019091905050610121565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a72305820b81379d1ae9d8e0fde05ee02b8bd170f43f8bd3d54da8b7ec203434a23a298980029" + + contract_address = insert(:contract_address, contract_code: bytecode) + + code = """ + pragma solidity ^0.4.15; + contract Incrementer { + event Incremented(address indexed sender, uint256 newValue); + uint256 public value; + address public lastSender; + function Incrementer(uint256 initialValue) { + value = initialValue; + lastSender = msg.sender; + } + function inc(uint256 delta) { + value = value + delta; + lastSender = msg.sender; + } + } + """ + + params = %{ + "contract_source_code" => code, + "compiler_version" => "v0.4.15+commit.bbb8e64f", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + test "returns error when constructor arguments do not match", %{ contract_code_info: contract_code_info } do