|
|
|
@ -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 <> <<metadata_hash::binary-size(64)>> <> "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::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> |
|
|
|
|
bytecode = |
|
|
|
|
extracted |
|
|
|
|
|> Enum.reverse() |
|
|
|
|
|> :binary.list_to_bin() |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"43" <> <<compiler_version::binary-size(6)>> <> "0032" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_10 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7826" <> <<compiler_version::binary-size(76)>> <> "0057" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_10 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7827" <> <<compiler_version::binary-size(78)>> <> "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::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7828" <> <<compiler_version::binary-size(80)>> <> "0058" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_10 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7829" <> <<compiler_version::binary-size(82)>> <> "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::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> |
|
|
|
|
bytecode = |
|
|
|
|
extracted |
|
|
|
|
|> Enum.reverse() |
|
|
|
|
|> :binary.list_to_bin() |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"43" <> <<compiler_version::binary-size(6)>> <> "0032" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_11 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7826" <> <<compiler_version::binary-size(76)>> <> "0057" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_11 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7827" <> <<compiler_version::binary-size(78)>> <> "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::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7828" <> <<compiler_version::binary-size(80)>> <> "0058" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_5_11 <> |
|
|
|
|
<<metadata_hash::binary-size(64)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7829" <> <<compiler_version::binary-size(82)>> <> "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::binary-size(68)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> <<_::binary-size(6)>> <> "0033" <> _constructor_arguments -> |
|
|
|
|
bytecode = |
|
|
|
|
extracted |
|
|
|
|
|> Enum.reverse() |
|
|
|
|
|> :binary.list_to_bin() |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"43" <> <<compiler_version::binary-size(6)>> <> "0033" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_6_0 <> |
|
|
|
|
<<metadata_hash::binary-size(68)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7826" <> <<compiler_version::binary-size(76)>> <> "0057" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_6_0 <> |
|
|
|
|
<<metadata_hash::binary-size(68)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7827" <> <<compiler_version::binary-size(78)>> <> "0057" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
@metadata_hash_prefix_0_6_0 <> |
|
|
|
|
<<metadata_hash::binary-size(68)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7828" <> <<compiler_version::binary-size(80)>> <> "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::binary-size(68)>> <> |
|
|
|
|
@metadata_hash_common_suffix <> |
|
|
|
|
"7829" <> <<compiler_version::binary-size(82)>> <> "0059" <> _constructor_arguments -> |
|
|
|
|
do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) |
|
|
|
|
|
|
|
|
|
<<next::binary-size(2)>> <> 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) |
|
|
|
|
|
|
|
|
|