From e1cdd757aa142aa6fb5df11d887a295353fae563 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Fri, 15 May 2020 12:36:02 +0300 Subject: [PATCH] Verification: check compiler version --- CHANGELOG.md | 5 +- .../lib/explorer/chain/smart_contract.ex | 1 + .../lib/explorer/smart_contract/verifier.ex | 151 +++++++--- .../verifier/constructor_arguments.ex | 141 ++++++++- .../explorer/smart_contract/verifier_test.exs | 283 +++++++++++++++++- 5 files changed, 534 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 475e409e26..883d97f951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,10 @@ ### Features ### Fixes -- [#3106](https://github.com/poanetwork/blockscout/pull/3106) - Verify contract using creation tx input +- [#3112](https://github.com/poanetwork/blockscout/pull/3112) - Fix verification of contracts, compiled with nightly builds of solc compiler +- [#3112](https://github.com/poanetwork/blockscout/pull/3112) - Check compiler version at contract verification +- [#3106](https://github.com/poanetwork/blockscout/pull/3106) - Fix verification of contracts with `immutable` declaration +- [#3106](https://github.com/poanetwork/blockscout/pull/3106) - Fix verification of contracts, created from factory (from internal transaction) ### Chore diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 0db7d7e613..9d4c03134a 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -326,6 +326,7 @@ defmodule Explorer.Chain.SmartContract do defp upsert_contract_methods(changeset), do: changeset defp error_message(:compilation), do: "There was an error compiling your contract." + defp error_message(:compiler_version), do: "Compiler version does not match, please try again." defp error_message(:generated_bytecode), do: "Bytecode does 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." diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 979fb1128d..1b4eb88a3e 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -1,3 +1,4 @@ +# credo:disable-for-this-file defmodule Explorer.SmartContract.Verifier do @moduledoc """ Module responsible to verify the Smart Contract. @@ -16,7 +17,7 @@ defmodule Explorer.SmartContract.Verifier do @metadata_hash_prefix_0_5_11 "a265627a7a72315820" @metadata_hash_prefix_0_6_0 "a264697066735822" - @metadata_hash_common_suffix "64736f6c6343" + @metadata_hash_common_suffix "64736f6c63" def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name} @@ -83,19 +84,28 @@ defmodule Explorer.SmartContract.Verifier do contract_source_code, contract_name ) do - %{"metadata_hash" => _generated_metadata_hash, "bytecode" => generated_bytecode} = - extract_bytecode_and_metadata_hash(bytecode) + %{ + "metadata_hash" => _generated_metadata_hash, + "bytecode" => generated_bytecode, + "compiler_version" => generated_compiler_version + } = extract_bytecode_and_metadata_hash(bytecode) "0x" <> blockchain_created_tx_input = address_hash |> Chain.smart_contract_creation_tx_bytecode() - %{"metadata_hash" => _metadata_hash, "bytecode" => blockchain_bytecode_without_whisper} = - extract_bytecode_and_metadata_hash(blockchain_created_tx_input) + %{ + "metadata_hash" => _metadata_hash, + "bytecode" => blockchain_bytecode_without_whisper, + "compiler_version" => compiler_version + } = extract_bytecode_and_metadata_hash(blockchain_created_tx_input) empty_constructor_arguments = arguments_data == "" or arguments_data == nil cond do + generated_compiler_version != compiler_version -> + {:error, :compiler_version} + generated_bytecode != blockchain_bytecode_without_whisper && !try_library_verification(generated_bytecode, blockchain_bytecode_without_whisper) -> {:error, :generated_bytecode} @@ -147,54 +157,86 @@ defmodule Explorer.SmartContract.Verifier do https://solidity.readthedocs.io/en/v0.5.3/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode """ def extract_bytecode_and_metadata_hash("0x" <> code) do - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} = extract_bytecode_and_metadata_hash(code) - %{"metadata_hash" => metadata_hash, "bytecode" => "0x" <> bytecode} + %{"metadata_hash" => metadata_hash, "bytecode" => bytecode, "compiler_version" => compiler_version} = + extract_bytecode_and_metadata_hash(code) + + %{"metadata_hash" => metadata_hash, "bytecode" => "0x" <> bytecode, "compiler_version" => compiler_version} end def extract_bytecode_and_metadata_hash(code) do - do_extract_bytecode_and_metadata_hash([], String.downcase(code), "") + do_extract_bytecode_and_metadata_hash([], String.downcase(code), nil, nil) end - defp do_extract_bytecode_and_metadata_hash(extracted, remaining, metadata_hash) do + defp do_extract_bytecode_and_metadata_hash(extracted, remaining, metadata_hash, compiler_version) do case remaining do <<>> -> - bytecode = - extracted - |> Enum.reverse() - |> :binary.list_to_bin() - - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) @metadata_hash_prefix_0_4_23 <> <> <> "0029" <> _constructor_arguments -> - bytecode = - extracted - |> Enum.reverse() - |> :binary.list_to_bin() - - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) # Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst @metadata_hash_prefix_0_5_10 <> <> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> - bytecode = - extracted - |> Enum.reverse() - |> :binary.list_to_bin() + @metadata_hash_common_suffix <> + "43" <> <> <> "0032" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_10 <> + <> <> + @metadata_hash_common_suffix <> + "7826" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_10 <> + <> <> + @metadata_hash_common_suffix <> + "7827" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} + @metadata_hash_prefix_0_5_10 <> + <> <> + @metadata_hash_common_suffix <> + "7828" <> <> <> "0058" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_10 <> + <> <> + @metadata_hash_common_suffix <> + "7829" <> <> <> "0059" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) # Solidity >= 0.5.11 https://github.com/ethereum/solidity/blob/develop/Changelog.md#0511-2019-08-12 # Metadata: Update the swarm hash to the current specification, changes bzzr0 to bzzr1 and urls to use bzz-raw:// @metadata_hash_prefix_0_5_11 <> <> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> - bytecode = - extracted - |> Enum.reverse() - |> :binary.list_to_bin() + @metadata_hash_common_suffix <> + "43" <> <> <> "0032" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_11 <> + <> <> + @metadata_hash_common_suffix <> + "7826" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_11 <> + <> <> + @metadata_hash_common_suffix <> + "7827" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} + @metadata_hash_prefix_0_5_11 <> + <> <> + @metadata_hash_common_suffix <> + "7828" <> <> <> "0058" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_5_11 <> + <> <> + @metadata_hash_common_suffix <> + "7829" <> <> <> "0059" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) # Solidity >= 0.6.0 https://github.com/ethereum/solidity/blob/develop/Changelog.md#060-2019-12-17 # https://github.com/ethereum/solidity/blob/26b700771e9cc9c956f0503a05de69a1be427963/docs/metadata.rst#encoding-of-the-metadata-hash-in-the-bytecode @@ -208,19 +250,48 @@ defmodule Explorer.SmartContract.Verifier do # Fixing PR has been created https://github.com/ethereum/solidity/pull/8174 @metadata_hash_prefix_0_6_0 <> <> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0033" <> _constructor_arguments -> - bytecode = - extracted - |> Enum.reverse() - |> :binary.list_to_bin() + @metadata_hash_common_suffix <> + "43" <> <> <> "0033" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_6_0 <> + <> <> + @metadata_hash_common_suffix <> + "7826" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_6_0 <> + <> <> + @metadata_hash_common_suffix <> + "7827" <> <> <> "0057" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) + + @metadata_hash_prefix_0_6_0 <> + <> <> + @metadata_hash_common_suffix <> + "7828" <> <> <> "0058" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) - %{"metadata_hash" => metadata_hash, "bytecode" => bytecode} + @metadata_hash_prefix_0_6_0 <> + <> <> + @metadata_hash_common_suffix <> + "7829" <> <> <> "0059" <> _constructor_arguments -> + do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) <> <> rest -> - do_extract_bytecode_and_metadata_hash([next | extracted], rest, metadata_hash) + do_extract_bytecode_and_metadata_hash([next | extracted], rest, metadata_hash, compiler_version) end end + defp do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) do + bytecode = + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + + %{"metadata_hash" => metadata_hash, "bytecode" => bytecode, "compiler_version" => compiler_version} + end + def previous_evm_versions(current_evm_version) do index = Enum.find_index(CodeCompiler.allowed_evm_versions(), fn el -> el == current_evm_version end) 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 a647034094..8edc758693 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex @@ -1,3 +1,4 @@ +# credo:disable-for-this-file defmodule Explorer.SmartContract.Verifier.ConstructorArguments do @moduledoc """ Smart contract contrstructor arguments verification logic. @@ -10,7 +11,7 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do @metadata_hash_prefix_0_5_11 "a265627a7a72315820" @metadata_hash_prefix_0_6_0 "a264697066735822" - @metadata_hash_common_suffix "64736f6c6343" + @metadata_hash_common_suffix "64736f6c63" def verify(address_hash, contract_code, arguments_data, contract_source_code, contract_name) do arguments_data = arguments_data |> String.trim_trailing() |> String.trim_leading("0x") @@ -53,7 +54,51 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do # Solidity >= 0.5.10 https://solidity.readthedocs.io/en/v0.5.10/metadata.html @metadata_hash_prefix_0_5_10 <> <<_::binary-size(64)>> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> + @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_10 + ) + + @metadata_hash_prefix_0_5_10 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_10 + ) + + @metadata_hash_prefix_0_5_10 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_10 + ) + + @metadata_hash_prefix_0_5_10 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_10 + ) + + @metadata_hash_prefix_0_5_10 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments -> split_constructor_arguments_and_extract_check_func( constructor_arguments, check_func, @@ -66,7 +111,51 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do # Metadata: Update the swarm hash to the current specification, changes bzzr0 to bzzr1 and urls to use bzz-raw:// @metadata_hash_prefix_0_5_11 <> <<_::binary-size(64)>> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> + @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_11 + ) + + @metadata_hash_prefix_0_5_11 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_11 + ) + + @metadata_hash_prefix_0_5_11 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_11 + ) + + @metadata_hash_prefix_0_5_11 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_5_11 + ) + + @metadata_hash_prefix_0_5_11 <> + <<_::binary-size(64)>> <> + @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments -> split_constructor_arguments_and_extract_check_func( constructor_arguments, check_func, @@ -87,7 +176,51 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do # Fixing PR has been created https://github.com/ethereum/solidity/pull/8174 @metadata_hash_prefix_0_6_0 <> <<_::binary-size(68)>> <> - @metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0033" <> constructor_arguments -> + @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0033" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_6_0 + ) + + @metadata_hash_prefix_0_6_0 <> + <<_::binary-size(68)>> <> + @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_6_0 + ) + + @metadata_hash_prefix_0_6_0 <> + <<_::binary-size(68)>> <> + @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_6_0 + ) + + @metadata_hash_prefix_0_6_0 <> + <<_::binary-size(68)>> <> + @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments -> + split_constructor_arguments_and_extract_check_func( + constructor_arguments, + check_func, + contract_source_code, + contract_name, + @metadata_hash_prefix_0_6_0 + ) + + @metadata_hash_prefix_0_6_0 <> + <<_::binary-size(68)>> <> + @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments -> split_constructor_arguments_and_extract_check_func( constructor_arguments, check_func, diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 0500fc4a3d..8199a5600c 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -7,6 +7,57 @@ defmodule Explorer.SmartContract.VerifierTest do alias Explorer.SmartContract.Verifier alias Explorer.Factory + @code_0_4 """ + pragma solidity ^0.4.0; + contract Incrementer { + event Incremented(address indexed sender, uint256 newValue); + uint256 public value; + address public lastSender; + constructor(uint256 initialValue) public { + value = initialValue; + lastSender = msg.sender; + } + function inc(uint256 delta) public { + value = value + delta; + lastSender = msg.sender; + } + } + """ + + @code_0_5 """ + pragma solidity ^0.5.0; + contract Incrementer { + event Incremented(address indexed sender, uint256 newValue); + uint256 public value; + address public lastSender; + constructor(uint256 initialValue) public { + value = initialValue; + lastSender = msg.sender; + } + function inc(uint256 delta) public { + value = value + delta; + lastSender = msg.sender; + } + } + """ + + @code_0_6 """ + pragma solidity ^0.6.0; + contract Incrementer { + event Incremented(address indexed sender, uint256 newValue); + uint256 public value; + address public lastSender; + constructor(uint256 initialValue) public { + value = initialValue; + lastSender = msg.sender; + } + function inc(uint256 delta) public { + value = value + delta; + lastSender = msg.sender; + } + } + """ + describe "evaluate_authenticity/2" do setup do {:ok, contract_code_info: Factory.contract_code_info()} @@ -301,7 +352,7 @@ defmodule Explorer.SmartContract.VerifierTest do bytecode = "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" - %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code} = + %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code, "compiler_version" => _compiler_version} = Verifier.extract_bytecode_and_metadata_hash(code) assert bytecode == bytecode_from_code @@ -320,7 +371,7 @@ defmodule Explorer.SmartContract.VerifierTest do bytecode = "0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" - %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code} = + %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code, "compiler_version" => _compiler_version} = Verifier.extract_bytecode_and_metadata_hash(code) assert bytecode == bytecode_from_code @@ -425,4 +476,232 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end end + + describe "compiler version tests" do + test "verification is failed if wrong version of compiler" do + bytecode_0_5_10 = + "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_10) + bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.11+commit.c082d0b4", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + response = Verifier.evaluate_authenticity(contract_address.hash, params) + assert {:error, :compiler_version} = response + end + + test "verification is successful if proper version of compiler" do + bytecode_0_5_10 = + "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_10) + bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.10+commit.5a6ea5b1", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + end + + describe "verification with nightly builds" do + test "verification is successful if proper nightly version of compiler ~0.4" do + bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2 = + "0x608060405234801561001057600080fd5b5060405160208061023d833981018060405281019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101b28061008b6000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063256fec881461005c5780633fa4f245146100b3578063812600df146100de575b600080fd5b34801561006857600080fd5b5061007161010b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100bf57600080fd5b506100c8610131565b6040518082815260200191505060405180910390f35b3480156100ea57600080fd5b5061010960048036038101908080359060200190929190505050610137565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a723058202d622d653be0a507f7ac0bc89d8934ccdbaf5e127abd603c3864a462149885070029" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2) + bytecode_construtor_arguments = "#{bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_4, + "compiler_version" => "v0.4.24-nightly.2018.4.26+commit.ef2111a2", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "verification is successful if proper nightly version of compiler ~0.5.10" do + bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4 = + "0x608060405234801561001057600080fd5b5060405161026a38038061026a8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101ce8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a723058208d4e3fa9b2179a8384e617e388dde334be1b44e7b11b42ab964ab1050e7cedca64736f6c637827302e352e31302d6e696768746c792e323031392e362e342b636f6d6d69742e39356536623265340057" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4) + bytecode_construtor_arguments = "#{bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.10-nightly.2019.6.4+commit.95e6b2e4", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "verification is successful if proper nightly version of compiler ~0.5.11" do + bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753 = + "0x608060405234801561001057600080fd5b5060405161026b38038061026b8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101cf8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820f7420b8c3b16d83ce728d8c279f0f887c4dcd7bfcd38c484acc9cdb82fde785764736f6c637828302e352e31312d6e696768746c792e323031392e362e32352b636f6d6d69742e31636338343735330058" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753) + bytecode_construtor_arguments = "#{bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.11-nightly.2019.6.25+commit.1cc84753", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "verification is successful if proper nightly version of compiler ~0.5.14" do + bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88 = + "0x608060405234801561001057600080fd5b5060405161026c38038061026c8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101d08061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820ec5a7ce04b1c2f97a3d3e61ae1b5cb06585e81c504542fd9668a8ead654da72764736f6c637829302e352e31342d6e696768746c792e323031392e31322e31302b636f6d6d69742e34356161376138380059" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88) + bytecode_construtor_arguments = "#{bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.14-nightly.2019.12.10+commit.45aa7a88", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "verification is successful if proper nightly version of compiler ~0.6.0" do + bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8 = + "0x608060405234801561001057600080fd5b5060405161026a38038061026a8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101ce8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea264697066735822122029b5dde5889a195ed02cebb1a638ae3754be34464b9a2bc8b48b6286636031fb64736f6c637826302e362e312d6e696768746c792e323032302e312e322b636f6d6d69742e64303832623962380057" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8) + bytecode_construtor_arguments = "#{bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_6, + "compiler_version" => "v0.6.1-nightly.2020.1.2+commit.d082b9b8", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + + test "verification is failed if wrong nightly version of compiler ~0.5.11" do + bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753 = + "0x608060405234801561001057600080fd5b5060405161026b38038061026b8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101cf8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820f7420b8c3b16d83ce728d8c279f0f887c4dcd7bfcd38c484acc9cdb82fde785764736f6c637828302e352e31312d6e696768746c792e323031392e362e32352b636f6d6d69742e31636338343735330058" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753) + bytecode_construtor_arguments = "#{bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.11-nightly.2019.8.10+commit.f5f2bbb2", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + response = Verifier.evaluate_authenticity(contract_address.hash, params) + assert {:error, :compiler_version} = response + end + end end