From e08b9f7ecc2cff2d6b9f97d6f8e4ba327f8232ab Mon Sep 17 00:00:00 2001 From: zachdaniel Date: Wed, 1 May 2019 10:33:09 -0400 Subject: [PATCH] fix: resolve false positive constructor arguments --- CHANGELOG.md | 1 + .../smart_contract/solidity/code_compiler.ex | 6 ++++ .../lib/explorer/smart_contract/verifier.ex | 31 ++++++++++++++----- .../explorer/smart_contract/verifier_test.exs | 18 ++++++++++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4b8db4d5..ca08e35fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - [#1885](https://github.com/poanetwork/blockscout/pull/1885) - highlight reserved words in decompiled code - [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete - [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance +- [#1875](https://github.com/poanetwork/blockscout/pull/1875) - fix: resolve false positive constructor arguments ### Chore 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 72c5bae186..3ded8ba9f1 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex @@ -63,6 +63,7 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do } } """ + @spec run(Keyword.t()) :: {:ok, map} | {:error, :compilation | :name} def run(params) do name = Keyword.fetch!(params, :name) compiler_version = Keyword.fetch!(params, :compiler_version) @@ -108,9 +109,14 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do {:error, %Jason.DecodeError{}} -> {:error, :compilation} + {:error, reason} when reason in [:name, :compilation] -> + {:error, reason} + error -> parse_error(error) end + else + {:error, :compilation} end end diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 0fc9f6b21b..746ba610aa 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -86,17 +86,32 @@ defmodule Explorer.SmartContract.Verifier do In order to discover the bytecode we need to remove the `swarm source` from the hash. - `64` characters to the left of `0029` are the `swarm source`. The rest on - the left is the `bytecode` to be validated. + For more information on the swarm hash, check out: + https://solidity.readthedocs.io/en/v0.5.3/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode """ + def extract_bytecode("0x" <> code) do + "0x" <> extract_bytecode(code) + end + def extract_bytecode(code) do - {bytecode, _swarm_source} = - code - |> String.split("0029") - |> List.first() - |> String.split_at(-64) + do_extract_bytecode([], String.downcase(code)) + end - bytecode + defp do_extract_bytecode(extracted, remaining) do + case remaining do + <<>> -> + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + + "a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> _constructor_arguments -> + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + + <> <> rest -> + do_extract_bytecode([next | extracted], rest) + end end def next_evm_version(current_evm_version) do diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 631c15695e..6786e559df 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -181,7 +181,7 @@ defmodule Explorer.SmartContract.VerifierTest do swarm_source = "3c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b" bytecode = - "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820" + "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" assert bytecode == Verifier.extract_bytecode(code) assert bytecode != code @@ -189,5 +189,21 @@ defmodule Explorer.SmartContract.VerifierTest do assert String.contains?(bytecode, "0029") == false assert String.contains?(bytecode, swarm_source) == false end + + test "extracts everything to the left of the swarm hash" do + code = + "0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058203c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b0029" + + swarm_source = "3c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b" + + bytecode = + "0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600" + + assert bytecode == Verifier.extract_bytecode(code) + assert bytecode != code + assert String.contains?(code, bytecode) == true + assert String.contains?(bytecode, "0029") == true + assert String.contains?(bytecode, swarm_source) == false + end end end