From 77c8357aed79a8ddb746f61e2988d579d2a1d830 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 5 Feb 2019 15:58:18 +0300 Subject: [PATCH] pass external_libraries form params from view to the verifier --- ...ddress_contract_verification_controller.ex | 14 ++++--- .../lib/explorer/smart_contract/publisher.ex | 25 +++++++++++- .../smart_contract/publisher_test.exs | 39 +++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex index ced6b9e845..3a725d989f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex @@ -16,11 +16,15 @@ defmodule BlockScoutWeb.AddressContractVerificationController do render(conn, "new.html", changeset: changeset, compiler_versions: compiler_versions) end - def create(conn, %{ - "address_id" => address_hash_string, - "smart_contract" => smart_contract - }) do - case Publisher.publish(address_hash_string, smart_contract) do + def create( + conn, + params = %{ + "address_id" => address_hash_string, + "smart_contract" => smart_contract, + "external_libraries" => external_libraries + } + ) do + case Publisher.publish(address_hash_string, smart_contract, external_libraries) do {:ok, _smart_contract} -> redirect(conn, to: address_contract_path(conn, :index, address_hash_string)) diff --git a/apps/explorer/lib/explorer/smart_contract/publisher.ex b/apps/explorer/lib/explorer/smart_contract/publisher.ex index 8a9b31e2b9..ef2a986ca2 100644 --- a/apps/explorer/lib/explorer/smart_contract/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/publisher.ex @@ -23,8 +23,10 @@ defmodule Explorer.SmartContract.Publisher do #=> {:ok, %Explorer.Chain.SmartContract{}} """ - def publish(address_hash, params) do - case Verifier.evaluate_authenticity(address_hash, params) do + def publish(address_hash, params, external_libraries \\ %{}) do + params_with_external_libaries = add_external_libraries(params, external_libraries) + + case Verifier.evaluate_authenticity(address_hash, params_with_external_libaries) do {:ok, %{abi: abi}} -> publish_smart_contract(address_hash, params, abi) @@ -62,4 +64,23 @@ defmodule Explorer.SmartContract.Publisher do abi: abi } end + + defp add_external_libraries(params, external_libraries) do + clean_external_libraries = + Enum.reduce(1..5, %{}, fn number, acc -> + address_key = "library#{number}_address" + name_key = "library#{number}_name" + + address = external_libraries[address_key] + name = external_libraries[name_key] + + if is_nil(address) || address == "" || is_nil(name) || name == "" do + acc + else + Map.put(acc, name, address) + end + end) + + Map.put(params, "external_libraries", clean_external_libraries) + end end diff --git a/apps/explorer/test/explorer/smart_contract/publisher_test.exs b/apps/explorer/test/explorer/smart_contract/publisher_test.exs index 9f219843b0..00641478bd 100644 --- a/apps/explorer/test/explorer/smart_contract/publisher_test.exs +++ b/apps/explorer/test/explorer/smart_contract/publisher_test.exs @@ -45,5 +45,44 @@ defmodule Explorer.SmartContract.PublisherTest do assert {:error, %Ecto.Changeset{}} = Publisher.publish(address_hash, invalid_attrs) end + + test "validates and creates smart contract with external libraries" do + contract_data = + "#{System.cwd!()}/test/support/fixture/smart_contract/compiler_tests.json" + |> File.read!() + |> Jason.decode!() + |> List.first() + + compiler_version = contract_data["compiler_version"] + external_libraries = contract_data["external_libraries"] + name = contract_data["name"] + optimize = contract_data["optimize"] + contract = contract_data["contract"] + expected_bytecode = contract_data["expected_bytecode"] + + contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode) + + params = %{ + "contract_source_code" => contract, + "compiler_version" => compiler_version, + "name" => name, + "optimization" => optimize + } + + external_libraries_form_params = + external_libraries + |> Enum.with_index() + |> Enum.reduce(%{}, fn {{name, address}, index}, acc -> + name_key = "library#{index + 1}_name" + address_key = "library#{index + 1}_address" + + acc + |> Map.put(name_key, name) + |> Map.put(address_key, address) + end) + + response = Publisher.publish(contract_address.hash, params, external_libraries_form_params) + assert {:ok, %SmartContract{} = smart_contract} = response + end end end