From 4f8dceed1cb09f87e753554e023424f4edaf560a Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 24 Jun 2019 10:41:45 +0300 Subject: [PATCH 1/5] fix metadata decomdiing in smart contract verification --- apps/explorer/lib/explorer/smart_contract/verifier.ex | 6 ++++++ .../smart_contract/verifier/constructor_arguments.ex | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 2dd6545010..ea25d24818 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -107,6 +107,12 @@ defmodule Explorer.SmartContract.Verifier do |> Enum.reverse() |> :binary.list_to_bin() + # Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst + "a265627a7a72305820" <> <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> + extracted + |> Enum.reverse() + |> :binary.list_to_bin() + <> <> rest -> do_extract_bytecode([next | extracted], rest) 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 aa32d85bb6..de888c0f97 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex @@ -21,6 +21,11 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do constructor_arguments end + # Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst + defp extract_contrstructor_arguments("a265627a7a72305820" <> <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments) do + constructor_arguments + end + defp extract_constructor_arguments(<<_::binary-size(2)>> <> rest) do extract_constructor_arguments(rest) end From 680c28866c3dc90765e23c27ca60ab97915da0a8 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 24 Jun 2019 11:27:02 +0300 Subject: [PATCH 2/5] fix typo --- .../smart_contract/verifier/constructor_arguments.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 de888c0f97..d6d1572f10 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex @@ -22,7 +22,10 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do end # Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst - defp extract_contrstructor_arguments("a265627a7a72305820" <> <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments) do + defp extract_constructor_arguments( + "a265627a7a72305820" <> + <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments + ) do constructor_arguments end From 74e969a45d4318c6efb9a70b5acaf65d5ae6c18a Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 24 Jun 2019 11:51:15 +0300 Subject: [PATCH 3/5] add regression test --- .../lib/explorer/smart_contract/verifier.ex | 3 +- .../explorer/smart_contract/verifier_test.exs | 32 ++++++++ .../solidity_0.5.9_smart_contract.sol | 76 +++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 apps/explorer/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index ea25d24818..f4e486fd50 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -108,7 +108,8 @@ defmodule Explorer.SmartContract.Verifier do |> :binary.list_to_bin() # Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst - "a265627a7a72305820" <> <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> + "a265627a7a72305820" <> + <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments -> extracted |> Enum.reverse() |> :binary.list_to_bin() diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index ef635c2573..9633804c60 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -117,6 +117,38 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end + test "verifies smart contract compiled with Solidity 0.5.9 (includes new metadata in bytecode) with constructor args" do + path = File.cwd!() <> "/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol" + contract = File.read!(path) + + constructor_arguments = + "00000000000000000000000000000000000000000000003635c9adc5dea000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000a54657374546f6b656e32000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006546f6b656e320000000000000000000000000000000000000000000000000000" + + bytecode = + "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820fe0ba5210ac95870683c2cb054304b04565703bd16c7d7e956df694c9643c6d264736f6c63430005090032" + + contract_address = insert(:contract_address, contract_code: bytecode) + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode <> constructor_arguments + ) + |> with_block() + + params = %{ + "contract_source_code" => contract, + "compiler_version" => "v0.5.9+commit.e560f70d", + "evm_version" => "petersburg", + "name" => "TestToken", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) + assert abi != nil + end + test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) diff --git a/apps/explorer/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol b/apps/explorer/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol new file mode 100644 index 0000000000..25601a98b6 --- /dev/null +++ b/apps/explorer/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol @@ -0,0 +1,76 @@ +pragma solidity ^0.5.9; +contract Token { + function totalSupply() public view returns (uint256 supply) {} + function balanceOf(address _owner) public view returns (uint256 balance) {} + function transfer(address _to, uint256 _value) public returns (bool success) {} + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {} + function approve(address _spender, uint256 _value) public returns (bool success) {} + function allowance(address _owner, address _spender) public view returns (uint256 remaining) {} + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); +} + + +contract StandardToken is Token { + function transfer(address _to, uint256 _value) public returns (bool success) { + //if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) { + if (balances[msg.sender] >= _value && _value > 0) { + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + return true; + } else { return false; } + } + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { + //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) { + if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { + balances[_to] += _value; + balances[_from] -= _value; + allowed[_from][msg.sender] -= _value; + emit Transfer(_from, _to, _value); + return true; + } else { return false; } + } + function balanceOf(address _owner) public view returns (uint256 balance) { + return balances[_owner]; + } + function approve(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + return allowed[_owner][_spender]; + } + mapping (address => uint256) balances; + mapping (address => mapping (address => uint256)) allowed; + uint256 totalTokenSupply; +} + +contract TestToken is StandardToken { + + /* Public variables */ + string public name; + uint8 public decimals; + string public symbol; + string public version = '0.1'; + + constructor( + uint256 _initialAmount, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol + ) public { + balances[msg.sender] = _initialAmount; + totalTokenSupply = _initialAmount; + name = _tokenName; + decimals = _decimalUnits; + symbol = _tokenSymbol; + } + + function approveAndCall(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } +} \ No newline at end of file From 402775c457a292f567569e902c6d92ddc018a824 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 24 Jun 2019 11:54:09 +0300 Subject: [PATCH 4/5] add CHANGELOG entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4e62d4751..a59abeecac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,8 @@ - [#2173](https://github.com/poanetwork/blockscout/pull/2173) - handle correctly empty transactions - [#2174](https://github.com/poanetwork/blockscout/pull/2174) - fix reward channel joining - [#2186](https://github.com/poanetwork/blockscout/pull/2186) - fix net version test -- [#2167](https://github.com/poanetwork/blockscout/pull/2168) - feat: document eth rpc api mimicking endpoints +- [#2167](https://github.com/poanetwork/blockscout/pull/2168) - feat: document eth rpc api mimicking endpoints +- [#2225](https://github.com/poanetwork/blockscout/pull/2225) - fix metadata decoding in Solidity 0.5.9 smart contract verification ### Chore - [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version From 0a255264f66735a984c38878e9227c1d08657fe7 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 24 Jun 2019 16:19:12 +0300 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fbda34c9c..fdbf8b678f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ - [#2173](https://github.com/poanetwork/blockscout/pull/2173) - handle correctly empty transactions - [#2174](https://github.com/poanetwork/blockscout/pull/2174) - fix reward channel joining - [#2186](https://github.com/poanetwork/blockscout/pull/2186) - fix net version test -- [#2167](https://github.com/poanetwork/blockscout/pull/2168) - feat: document eth rpc api mimicking endpoints +- [#2167](https://github.com/poanetwork/blockscout/pull/2167) - feat: document eth rpc api mimicking endpoints - [#2225](https://github.com/poanetwork/blockscout/pull/2225) - fix metadata decoding in Solidity 0.5.9 smart contract verification ### Chore