Support multiple compile versions

This will allow that the versions selected in the page have
real impact on how the Contract will be verified.
pull/288/head
Igor Florian 7 years ago
parent 2ebd5eaf57
commit 44430af6f9
  1. 118
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  2. 8
      apps/explorer/lib/explorer/smart_contract/solidity/compiler_version.ex
  3. 14
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  4. 3
      apps/explorer/priv/compile_solc.js
  5. 40
      apps/explorer/test/explorer/smart_contract/publisher_test.exs
  6. 123
      apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
  7. 2
      apps/explorer/test/explorer/smart_contract/solidity/compiler_version_test.exs
  8. 85
      apps/explorer/test/explorer/smart_contract/verifier_test.exs
  9. 32
      apps/explorer/test/support/factory.ex
  10. 47
      apps/explorer_web/test/explorer_web/features/address_contract_verification_test.exs

@ -3,14 +3,36 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
Module responsible to compile the Solidity code of a given Smart Contract. Module responsible to compile the Solidity code of a given Smart Contract.
""" """
@doc ~S""" @doc """
Compiles a code in the solidity command line. Compiles a code in the solidity command line.
Returns a `Map`. Returns a `Map`.
## Examples ## Examples
iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run("SimpleStorage", "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }", false)
{:ok, %{ iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run(
...> "SimpleStorage",
...> "v0.4.24+commit.e67f0147",
...> \"""
...> pragma solidity ^0.4.24;
...>
...> contract SimpleStorage {
...> uint storedData;
...>
...> function set(uint x) public {
...> storedData = x;
...> }
...>
...> function get() public constant returns (uint) {
...> return storedData;
...> }
...> }
...> \""",
...> false
...> )
{
:ok,
%{
"abi" => [ "abi" => [
%{ %{
"constant" => false, "constant" => false,
@ -31,66 +53,66 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
"type" => "function" "type" => "function"
} }
], ],
"bytecode" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029", "bytecode" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820235fceab083d33bf112b473c85551306a29f32dcdc7e95b4dfdd697c1db188ec0029",
"name" => "SimpleStorage" "name" => "SimpleStorage",
}} "opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xDF DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x23 0x5f 0xce 0xab ADDMOD RETURNDATASIZE CALLER 0xbf GT 0x2b 0x47 EXTCODECOPY DUP6 SSTORE SGT MOD LOG2 SWAP16 ORIGIN 0xdc 0xdc PUSH31 0x95B4DFDD697C1DB188EC002900000000000000000000000000000000000000 "
}
}
""" """
def run(name, code, optimization) do def run(name, compiler_version, code, optimize) do
{response, _status} = {response, _status} =
System.cmd( System.cmd(
"node", "node",
[ [
Application.app_dir(:explorer, "priv/compile_solc.js"), Application.app_dir(:explorer, "priv/compile_solc.js"),
generate_settings(name, code, optimization), code,
"v0.4.24+commit.e67f0147" compiler_version,
optimize_value(optimize)
] ]
) )
case Jason.decode!(response) do with %{"contracts" => contracts} <- Jason.decode!(response),
%{"interface" => abi, "runtimeBytecode" => bytecode, "opcodes" => opcodes} <-
get_contract_info(contracts, name) do
{
:ok,
%{ %{
"contracts" => %{ "abi" => Jason.decode!(abi),
^name => %{ "bytecode" => bytecode,
^name => %{ "name" => name,
"abi" => abi, "opcodes" => opcodes
"evm" => %{
"bytecode" => %{"object" => bytecode}
}
} }
} }
} else
} -> error ->
{:ok, %{"abi" => abi, "bytecode" => bytecode, "name" => name}} parse_error(error)
end
end
def get_contract_info(contracts, _) when contracts == %{}, do: %{"errors" => []}
def get_contract_info(contracts, name) do
new_versions_name = ":" <> name
case contracts do
%{^new_versions_name => response} ->
response
%{^name => response} ->
response
_ -> _ ->
{:error, :compilation} {:error, :name}
end end
end end
@doc """ def parse_error({:error, :name} = error), do: error
For more output options check the documentation. def parse_error(%{"error" => error}), do: {:error, [error]}
https://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html#compiler-input-and-output-json-description def parse_error(%{"errors" => errors}), do: {:error, errors}
"""
def generate_settings(name, code, optimization) do defp optimize_value(false), do: "0"
""" defp optimize_value("false"), do: "0"
{
"language": "Solidity", defp optimize_value(true), do: "1"
"sources": { defp optimize_value("true"), do: "1"
"#{name}":
{
"content": "#{code}"
}
},
"settings": {
"optimizer": {
"enabled": #{optimization}
},
"outputSelection": {
"*": {
"*": [ "evm.bytecode", "evm.deployedBytecode", "evm.gasEstimates", "abi", "metadata" ]
}
}
}
}
"""
end
end end

@ -30,11 +30,17 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersion do
releases releases
|> Map.to_list() |> Map.to_list()
|> Enum.map(fn {key, _value} -> {key, key} end) |> Enum.map(fn {key, value} -> {key, extract_version(value)} end)
|> Enum.sort() |> Enum.sort()
|> Enum.reverse() |> Enum.reverse()
end end
defp extract_version(version) do
version
|> String.replace_prefix("soljson-", "")
|> String.replace_suffix(".js", "")
end
defp decode_json(json) do defp decode_json(json) do
Jason.decode!(json) Jason.decode!(json)
end end

@ -11,18 +11,24 @@ defmodule Explorer.SmartContract.Verifier do
alias Explorer.SmartContract.Solidity.CodeCompiler alias Explorer.SmartContract.Solidity.CodeCompiler
def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name} def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name}
def evaluate_authenticity(_, %{"contract_source_code" => ""}), do: {:error, :contract_source_code}
def evaluate_authenticity(_, %{"contract_source_code" => ""}),
do: {:error, :contract_source_code}
def evaluate_authenticity(address_hash, %{ def evaluate_authenticity(address_hash, %{
"name" => name, "name" => name,
"contract_source_code" => contract_source_code, "contract_source_code" => contract_source_code,
"optimization" => optimization "optimization" => optimization,
"compiler" => compiler_version
}) do }) do
solc_output = CodeCompiler.run(name, contract_source_code, optimization)
solc_output = CodeCompiler.run(name, compiler_version, contract_source_code, optimization)
compare_bytecodes(solc_output, address_hash) compare_bytecodes(solc_output, address_hash)
end end
defp compare_bytecodes(compilation_error = {:error, _}, _), do: compilation_error defp compare_bytecodes({:error, :name}, _), do: {:error, :name}
defp compare_bytecodes({:error, _}, _), do: {:error, :compilation}
defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash) do defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash) do
generated_bytecode = extract_bytecode(bytecode) generated_bytecode = extract_bytecode(bytecode)

@ -4,11 +4,12 @@ const solc = require('solc-js');
var sourceCode = process.argv[2]; var sourceCode = process.argv[2];
var version = process.argv[3]; var version = process.argv[3];
var optimize = process.argv[4];
var compiled_code = solc.loadRemoteVersion(version, function (err, solcSnapshot) { var compiled_code = solc.loadRemoteVersion(version, function (err, solcSnapshot) {
if (err) { if (err) {
console.log(JSON.stringify(err)); console.log(JSON.stringify(err));
} else { } else {
console.log(solcSnapshot.compileStandardWrapper(sourceCode)); console.log(JSON.stringify(solcSnapshot.compile(sourceCode, optimize)));
} }
}); });

@ -5,43 +5,29 @@ defmodule Explorer.SmartContract.PublisherTest do
doctest Explorer.SmartContract.Publisher doctest Explorer.SmartContract.Publisher
alias Explorer.Chain.{SmartContract, Hash} alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.Publisher alias Explorer.SmartContract.Publisher
alias Explorer.Factory
describe "publish/2" do describe "publish/2" do
test "with valid data creates a smart_contract" do test "with valid data creates a smart_contract" do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_code_info = Factory.contract_code_info()
smart_contract_bytecode = contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction_create,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
valid_attrs = %{ valid_attrs = %{
"contract_source_code" => "contract_source_code" => contract_code_info.source_code,
"pragma solidity ^0.4.23;\r\n\r\ncontract SimpleStorage {\r\n uint storedData;\r\n\r\n function set(uint x) public {\r\n storedData = x;\r\n }\r\n\r\n function get() public constant returns (uint) {\r\n return storedData;\r\n }\r\n}", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:ok, %SmartContract{} = smart_contract} = Publisher.publish(address_hash, valid_attrs) response = Publisher.publish(contract_address.hash, valid_attrs)
assert {:ok, %SmartContract{} = smart_contract} = response
assert smart_contract.address_hash == contract_address.hash
assert smart_contract.name == valid_attrs["name"] assert smart_contract.name == valid_attrs["name"]
assert Hash.to_string(smart_contract.address_hash) == address_hash assert smart_contract.compiler_version == valid_attrs["compiler_version"]
assert smart_contract.compiler_version == valid_attrs["compiler"]
assert smart_contract.optimization == valid_attrs["optimization"] assert smart_contract.optimization == valid_attrs["optimization"]
assert smart_contract.contract_source_code == valid_attrs["contract_source_code"] assert smart_contract.contract_source_code == valid_attrs["contract_source_code"]
assert smart_contract.abi != nil assert smart_contract.abi != nil

@ -4,15 +4,56 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
doctest Explorer.SmartContract.Solidity.CodeCompiler doctest Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.SmartContract.Solidity.CodeCompiler alias Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.Factory
describe "run/2" do describe "run/2" do
test "compiles a smart contract using the solidity command line" do setup do
{:ok, contract_code_info: Factory.contract_code_info()}
end
test "compiles the latest solidity version", %{contract_code_info: contract_code_info} do
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
contract_code_info.source_code,
contract_code_info.optimized
)
assert {:ok,
%{
"abi" => _,
"bytecode" => _,
"name" => _,
"opcodes" => _
}} = response
end
test "compiles a optimized smart contract", %{contract_code_info: contract_code_info} do
optimize = true
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
contract_code_info.source_code,
optimize
)
assert {:ok,
%{
"abi" => _,
"bytecode" => _,
"name" => _,
"opcodes" => _
}} = response
end
test "compile in an older solidity version" do
optimize = false
name = "SimpleStorage" name = "SimpleStorage"
optimization = false
code = """ code = """
pragma solidity ^0.4.24;
contract SimpleStorage { contract SimpleStorage {
uint storedData; uint storedData;
@ -26,42 +67,74 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
} }
""" """
response = CodeCompiler.run(name, code, optimization) version = "v0.1.3-nightly.2015.9.25+commit.4457170"
response = CodeCompiler.run(name, version, code, optimize)
assert {:ok, assert {:ok,
%{ %{
"abi" => _, "abi" => _,
"bytecode" => _, "bytecode" => _,
"name" => _ "name" => _,
"opcodes" => _
}} = response }} = response
end end
test "returns a list of errors the compilation isn't possible", %{
contract_code_info: contract_code_info
} do
wrong_code = "pragma solidity ^0.4.24; cont SimpleStorage { "
response =
CodeCompiler.run(
contract_code_info.name,
contract_code_info.version,
wrong_code,
contract_code_info.optimized
)
assert {:error, errors} = response
assert is_list(errors)
end
end end
describe "generate_settings/2" do describe "get_contract_info/1" do
test "creates a json file with the solidity compiler expected settings" do test "return name error when the Contract name doesn't match" do
name = "SimpleStorage" name = "Name"
optimization = false different_name = "diff_name"
code = """ response = CodeCompiler.get_contract_info(%{name => %{}}, different_name)
pragma solidity ^0.4.24;
contract SimpleStorage { assert {:error, :name} == response
uint storedData; end
function set(uint x) public { test "returns an empty list of errors for empty info" do
storedData = x; name = "Name"
}
function get() public constant returns (uint) { response = CodeCompiler.get_contract_info(%{}, name)
return storedData;
} assert %{"errors" => []} == response
} end
"""
test "the contract info is returned when the name matches" do
contract_inner_info = %{"abi" => %{}, "bytecode" => "", "opcodes" => ""}
name = "Name"
contract_info = %{name => contract_inner_info}
response = CodeCompiler.get_contract_info(contract_info, name)
assert contract_inner_info == response
end
test "the contract info is returned when the name matches with a `:` sufix" do
name = "Name"
name_with_sufix = ":Name"
contract_inner_info = %{"abi" => %{}, "bytecode" => "", "opcodes" => ""}
contract_info = %{name_with_sufix => contract_inner_info}
generated = CodeCompiler.generate_settings(name, code, optimization) response = CodeCompiler.get_contract_info(contract_info, name)
assert String.contains?(generated, "contract SimpleStorage") == true assert contract_inner_info == response
assert String.contains?(generated, "settings") == true
end end
end end
end end

@ -24,7 +24,7 @@ defmodule Explorer.SmartContract.Solidity.CompilerVersionTest do
end) end)
assert {:ok, versions} = CompilerVersion.fetch_versions() assert {:ok, versions} = CompilerVersion.fetch_versions()
assert Enum.any?(versions, fn item -> item == {"0.4.9", "0.4.9"} end) == true assert Enum.any?(versions, fn item -> item == {"0.4.9", "v0.4.9+commit.364da425"} end) == true
end end
test "returns error when list of versions is not available", %{bypass: bypass} do test "returns error when list of versions is not available", %{bypass: bypass} do

@ -5,84 +5,57 @@ defmodule Explorer.SmartContract.VerifierTest do
doctest Explorer.SmartContract.Verifier doctest Explorer.SmartContract.Verifier
alias Explorer.SmartContract.Verifier alias Explorer.SmartContract.Verifier
alias Explorer.Factory
describe "evaluate_authenticity/2" do describe "evaluate_authenticity/2" do
test "verifies the generated bytecode against bytecode retrieved from the blockchain" do setup do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" {:ok, contract_code_info: Factory.contract_code_info()}
end
smart_contract_bytecode =
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert( test "verifies the generated bytecode against bytecode retrieved from the blockchain", %{
:internal_transaction_create, contract_code_info: contract_code_info
transaction: transaction, } do
index: 0, contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
params = %{ params = %{
"contract_source_code" => "contract_source_code" => contract_code_info.source_code,
"pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(address_hash, params) assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
assert abi != nil assert abi != nil
end end
test "returns error when bytecoed doesn't match" do test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
wrong_smart_contract_bytecode = different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}"
"0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058207722b6ddfe522b31e50b878ced2f22d051e8e2cd19be7b4fba9686602b90ba2b0029"
created_contract_address = insert(:address, hash: address_hash, contract_code: wrong_smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction_create,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: wrong_smart_contract_bytecode
)
params = %{ params = %{
"contract_source_code" => "contract_source_code" => different_code,
"pragma solidity ^0.4.24; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }", "compiler_version" => contract_code_info.version,
"compiler" => "0.4.24", "name" => contract_code_info.name,
"name" => "SimpleStorage", "optimization" => contract_code_info.optimized
"optimization" => false
} }
assert {:error, :generated_bytecode} = Verifier.evaluate_authenticity(address_hash, params) response = Verifier.evaluate_authenticity(contract_address.hash, params)
assert {:error, :generated_bytecode} = response
end end
test "returns error when there is a compilation problem" do test "returns error when there is a compilation problem", %{contract_code_info: contract_code_info} do
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
params = %{ params = %{
"contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { ", "contract_source_code" => "pragma solidity ^0.4.24; contract SimpleStorage { ",
"compiler" => "0.4.24", "compiler_version" => contract_code_info.version,
"name" => "SimpleStorage", "name" => contract_code_info.name,
"optimization" => false "optimization" => contract_code_info.optimized
} }
assert {:error, :compilation} = Verifier.evaluate_authenticity(address_hash, params) assert {:error, :compilation} = Verifier.evaluate_authenticity(contract_address.hash, params)
end end
end end

@ -29,6 +29,38 @@ defmodule Explorer.Factory do
} }
end end
def contract_address_factory do
%Address{
hash: address_hash(),
contract_code: Map.fetch!(contract_code_info(), :bytecode)
}
end
def contract_code_info do
%{
bytecode:
"0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820f65a3adc1cfb055013d1dc37d0fe98676e2a5963677fa7541a10386d163446680029",
name: "SimpleStorage",
source_code: """
pragma solidity ^0.4.24;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public constant returns (uint) {
return storedData;
}
}
""",
version: "v0.4.24+commit.e67f0147",
optimized: false
}
end
def address_hash do def address_hash do
{:ok, address_hash} = {:ok, address_hash} =
"address_hash" "address_hash"

@ -4,6 +4,7 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
import Wallaby.Query import Wallaby.Query
alias Plug.Conn alias Plug.Conn
alias Explorer.Factory
setup do setup do
bypass = Bypass.open() bypass = Bypass.open()
@ -16,51 +17,19 @@ defmodule ExplorerWeb.AddressContractVerificationTest do
test "users validates smart contract", %{session: session, bypass: bypass} do test "users validates smart contract", %{session: session, bypass: bypass} do
Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, solc_bin_versions()) end) Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, solc_bin_versions()) end)
address_hash = "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c" %{name: name, source_code: source_code, bytecode: bytecode, version: version} = Factory.contract_code_info()
smart_contract_bytecode = contract_address = insert(:contract_address, contract_code: bytecode)
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029"
created_contract_address = insert(:address, hash: address_hash, contract_code: smart_contract_bytecode)
transaction =
:transaction
|> insert()
|> with_block()
insert(
:internal_transaction,
transaction: transaction,
index: 0,
created_contract_address: created_contract_address,
created_contract_code: smart_contract_bytecode
)
code = """
pragma solidity ^0.4.24;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public constant returns (uint) {
return storedData;
}
}
"""
session session
|> visit("/en/addresses/#{address_hash}/contract_verifications/new") |> visit("/en/addresses/#{contract_address.hash}/contract_verifications/new")
|> fill_in(text_field("Contract Name"), with: "SimpleStorage") |> fill_in(text_field("Contract Name"), with: name)
|> click(option("0.4.24")) |> click(option(version))
|> click(radio_button("No")) |> click(radio_button("No"))
|> fill_in(text_field("Enter the Solidity Contract Code below"), with: code) |> fill_in(text_field("Enter the Solidity Contract Code below"), with: source_code)
|> click(button("Verify and publish")) |> click(button("Verify and publish"))
assert current_path(session) =~ ~r/\/en\/addresses\/#{address_hash}\/contracts/ assert current_path(session) =~ ~r/\/en\/addresses\/#{contract_address.hash}\/contracts/
end end
test "with invalid data shows error messages", %{session: session, bypass: bypass} do test "with invalid data shows error messages", %{session: session, bypass: bypass} do

Loading…
Cancel
Save