Proxy reader: handle function with params

pull/3157/head
Victor Baranov 5 years ago
parent 7adf3f4220
commit be69a0ce17
  1. 17
      apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
  2. 10
      apps/block_scout_web/test/block_scout_web/controllers/address_read_proxy_controller_test.exs
  3. 6
      apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs
  4. 23
      apps/explorer/lib/explorer/smart_contract/reader.ex
  5. 6
      apps/explorer/test/explorer/smart_contract/reader_test.exs

@ -38,13 +38,26 @@ defmodule BlockScoutWeb.SmartContractController do
def index(conn, _), do: not_found(conn)
def show(conn, params) do
address_options = [
necessity_by_association: %{
:contracts_creation_internal_transaction => :optional,
:names => :optional,
:smart_contract => :optional,
:token => :optional,
:contracts_creation_transaction => :optional
}
]
with true <- ajax?(conn),
{:ok, address_hash} <- Chain.string_to_address_hash(params["id"]),
:ok <- Chain.check_contract_address_exists(address_hash) do
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
contract_type = if Chain.is_proxy_contract?(address.smart_contract.abi), do: :proxy, else: :regular
outputs =
Reader.query_function(
address_hash,
%{name: params["function_name"], args: params["args"]}
%{name: params["function_name"], args: params["args"]},
contract_type
)
conn

@ -21,7 +21,7 @@ defmodule BlockScoutWeb.AddressReadProxyControllerTest do
end
test "with invalid address hash", %{conn: conn} do
conn = get(conn, address_read_contract_path(BlockScoutWeb.Endpoint, :index, "invalid_address"))
conn = get(conn, address_read_proxy_path(BlockScoutWeb.Endpoint, :index, "invalid_address"))
assert html_response(conn, 404)
end
@ -29,7 +29,7 @@ defmodule BlockScoutWeb.AddressReadProxyControllerTest do
test "with valid address that is not a contract", %{conn: conn} do
address = insert(:address)
conn = get(conn, address_read_contract_path(BlockScoutWeb.Endpoint, :index, Address.checksum(address.hash)))
conn = get(conn, address_read_proxy_path(BlockScoutWeb.Endpoint, :index, Address.checksum(address.hash)))
assert html_response(conn, 404)
end
@ -50,8 +50,7 @@ defmodule BlockScoutWeb.AddressReadProxyControllerTest do
insert(:smart_contract, address_hash: contract_address.hash)
conn =
get(conn, address_read_contract_path(BlockScoutWeb.Endpoint, :index, Address.checksum(contract_address.hash)))
conn = get(conn, address_read_proxy_path(BlockScoutWeb.Endpoint, :index, Address.checksum(contract_address.hash)))
assert html_response(conn, 200)
assert contract_address.hash == conn.assigns.address.hash
@ -72,8 +71,7 @@ defmodule BlockScoutWeb.AddressReadProxyControllerTest do
block_index: 0
)
conn =
get(conn, address_read_contract_path(BlockScoutWeb.Endpoint, :index, Address.checksum(contract_address.hash)))
conn = get(conn, address_read_proxy_path(BlockScoutWeb.Endpoint, :index, Address.checksum(contract_address.hash)))
assert html_response(conn, 404)
end

@ -22,7 +22,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
end
test "error for invalid address" do
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: "0x00", type: "regular")
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: "0x00", type: :regular)
conn =
build_conn()
@ -49,7 +49,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
blockchain_get_function_mock()
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: token_contract_address.hash, type: "regular")
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: token_contract_address.hash, type: :regular)
conn =
build_conn()
@ -65,7 +65,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
insert(:smart_contract, address_hash: token_contract_address.hash)
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: token_contract_address.hash, type: "proxy")
path = smart_contract_path(BlockScoutWeb.Endpoint, :index, hash: token_contract_address.hash, type: :proxy)
conn =
build_conn()

@ -221,26 +221,33 @@ defmodule Explorer.SmartContract.Reader do
@doc """
Fetches the blockchain value of a function that requires arguments.
"""
@spec query_function(String.t(), %{name: String.t(), args: nil}) :: [%{}]
def query_function(contract_address_hash, %{name: name, args: nil}) do
query_function(contract_address_hash, %{name: name, args: []})
@spec query_function(String.t(), %{name: String.t(), args: nil}, atom()) :: [%{}]
def query_function(contract_address_hash, %{name: name, args: nil}, type) do
query_function(contract_address_hash, %{name: name, args: []}, type)
end
@spec query_function(Hash.t(), %{name: String.t(), args: [term()]}) :: [%{}]
def query_function(contract_address_hash, %{name: name, args: args}) do
@spec query_function(Hash.t(), %{name: String.t(), args: [term()]}, atom()) :: [%{}]
def query_function(contract_address_hash, %{name: name, args: args}, type) do
abi =
contract_address_hash
|> Chain.address_hash_to_smart_contract()
|> Map.get(:abi)
final_abi =
if type == :proxy do
Chain.get_implementation_abi_from_proxy(contract_address_hash, abi)
else
abi
end
outputs =
case abi do
case final_abi do
nil ->
nil
_ ->
function =
abi
final_abi
|> Enum.filter(fn function -> function["name"] == name end)
|> List.first()
@ -248,7 +255,7 @@ defmodule Explorer.SmartContract.Reader do
end
contract_address_hash
|> query_verified_contract(%{name => normalize_args(args)}, abi)
|> query_verified_contract(%{name => normalize_args(args)}, final_abi)
|> link_outputs_and_values(outputs, name)
end

@ -262,7 +262,7 @@ defmodule Explorer.SmartContract.ReaderTest do
end
end
describe "query_function/2" do
describe "query_function/3" do
test "given the arguments, fetches the function value from the blockchain" do
smart_contract = insert(:smart_contract)
@ -274,7 +274,7 @@ defmodule Explorer.SmartContract.ReaderTest do
"type" => "uint256",
"value" => 0
}
] = Reader.query_function(smart_contract.address_hash, %{name: "get", args: []})
] = Reader.query_function(smart_contract.address_hash, %{name: "get", args: []}, :regular)
end
test "nil arguments is treated as []" do
@ -288,7 +288,7 @@ defmodule Explorer.SmartContract.ReaderTest do
"type" => "uint256",
"value" => 0
}
] = Reader.query_function(smart_contract.address_hash, %{name: "get", args: nil})
] = Reader.query_function(smart_contract.address_hash, %{name: "get", args: nil}, :regular)
end
end

Loading…
Cancel
Save