commit
3cc9a7c4f4
@ -0,0 +1,74 @@ |
||||
defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do |
||||
use BlockScoutWeb, :controller |
||||
|
||||
alias Explorer.Chain |
||||
alias Explorer.Chain.Hash.Address |
||||
alias Explorer.SmartContract.Publisher |
||||
|
||||
def create(conn, params) do |
||||
with {:ok, hash} <- validate_address_hash(params["address_hash"]), |
||||
:ok <- smart_contract_exists?(hash), |
||||
:ok <- verified_smart_contract_exists?(hash) do |
||||
external_libraries = fetch_external_libraries(params) |
||||
|
||||
case Publisher.publish(hash, params, external_libraries) do |
||||
{:ok, _} -> |
||||
send_resp(conn, :created, Jason.encode!(%{status: :success})) |
||||
|
||||
{:error, changeset} -> |
||||
errors = |
||||
changeset.errors |
||||
|> Enum.into(%{}, fn {field, {message, _}} -> |
||||
{field, message} |
||||
end) |
||||
|
||||
send_resp(conn, :unprocessable_entity, encode(errors)) |
||||
end |
||||
else |
||||
:invalid_address -> |
||||
send_resp(conn, :unprocessable_entity, encode(%{error: "address_hash is invalid"})) |
||||
|
||||
:not_found -> |
||||
send_resp(conn, :unprocessable_entity, encode(%{error: "address is not found"})) |
||||
|
||||
:contract_exists -> |
||||
send_resp( |
||||
conn, |
||||
:unprocessable_entity, |
||||
encode(%{error: "verified code already exists for this address"}) |
||||
) |
||||
end |
||||
end |
||||
|
||||
defp smart_contract_exists?(address_hash) do |
||||
case Chain.hash_to_address(address_hash) do |
||||
{:ok, _address} -> :ok |
||||
_ -> :not_found |
||||
end |
||||
end |
||||
|
||||
defp validate_address_hash(address_hash) do |
||||
case Address.cast(address_hash) do |
||||
{:ok, hash} -> {:ok, hash} |
||||
:error -> :invalid_address |
||||
end |
||||
end |
||||
|
||||
defp verified_smart_contract_exists?(address_hash) do |
||||
if Chain.address_hash_to_smart_contract(address_hash) do |
||||
:contract_exists |
||||
else |
||||
:ok |
||||
end |
||||
end |
||||
|
||||
defp encode(data) do |
||||
Jason.encode!(data) |
||||
end |
||||
|
||||
defp fetch_external_libraries(params) do |
||||
keys = Enum.flat_map(1..5, fn i -> ["library#{i}_name", "library#{i}_address"] end) |
||||
|
||||
Map.take(params, keys) |
||||
end |
||||
end |
@ -0,0 +1,72 @@ |
||||
defmodule BlockScoutWeb.API.V1.VerifiedControllerTest do |
||||
use BlockScoutWeb.ConnCase |
||||
|
||||
alias Explorer.Factory |
||||
# alias Explorer.Chain.DecompiledSmartContract |
||||
|
||||
# import Ecto.Query, |
||||
# only: [from: 2] |
||||
|
||||
test "verifying a standard smart contract", %{conn: conn} do |
||||
contract_code_info = Factory.contract_code_info() |
||||
|
||||
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) |
||||
|
||||
params = %{ |
||||
"address_hash" => to_string(contract_address.hash), |
||||
"name" => contract_code_info.name, |
||||
"compiler_version" => contract_code_info.version, |
||||
"optimization" => contract_code_info.optimized, |
||||
"contract_source_code" => contract_code_info.source_code |
||||
} |
||||
|
||||
response = post(conn, api_v1_verified_smart_contract_path(conn, :create), params) |
||||
|
||||
assert response.status == 201 |
||||
assert Jason.decode!(response.resp_body) == %{"status" => "success"} |
||||
end |
||||
|
||||
test "verifying a smart contract with external libraries", %{conn: conn} do |
||||
contract_data = |
||||
"#{File.cwd!()}/test/support/fixture/smart_contract/compiler_tests.json" |
||||
|> File.read!() |
||||
|> Jason.decode!() |
||||
|> List.first() |
||||
|
||||
%{ |
||||
"compiler_version" => compiler_version, |
||||
"external_libraries" => external_libraries, |
||||
"name" => name, |
||||
"optimize" => optimize, |
||||
"contract" => contract_source_code, |
||||
"expected_bytecode" => expected_bytecode |
||||
} = contract_data |
||||
|
||||
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode) |
||||
|
||||
params = %{ |
||||
"address_hash" => to_string(contract_address.hash), |
||||
"name" => name, |
||||
"compiler_version" => compiler_version, |
||||
"optimization" => optimize, |
||||
"contract_source_code" => contract_source_code |
||||
} |
||||
|
||||
params_with_external_libraries = |
||||
external_libraries |
||||
|> Enum.with_index() |
||||
|> Enum.reduce(params, 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 = post(conn, api_v1_verified_smart_contract_path(conn, :create), params_with_external_libraries) |
||||
|
||||
assert response.status == 201 |
||||
assert Jason.decode!(response.resp_body) == %{"status" => "success"} |
||||
end |
||||
end |
@ -0,0 +1,7 @@ |
||||
#!/bin/sh |
||||
|
||||
rm -rf ./_build |
||||
rm -rf ./deps |
||||
rm -rf ./logs/dev |
||||
rm -rf ./apps/explorer/node_modules |
||||
rm -rf ./apps/block_scout_web/assets/node_modules |
Loading…
Reference in new issue