feat: Support verifier alliance and eth-bytecode-db v1.7.0 changes (#9724)

* feat: Support verifier alliance and eth-bytecode-db v1.7.0 changes

* Fix bug and tests

* Add tests

* Process review comments
pull/9812/head
nikitosing 8 months ago committed by GitHub
parent 0f153faf94
commit 36df683929
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/import_controller.ex
  2. 1
      apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex
  3. 335
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs
  4. 43
      apps/block_scout_web/test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_partial_response.json
  5. 43
      apps/block_scout_web/test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_partial_response_eth_bdb_full.json
  6. 43
      apps/block_scout_web/test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_response.json
  7. 2
      apps/block_scout_web/test/support/fixture/smart_contract/eth_bytecode_db_search_all_sourcify_sources_response.json
  8. 12
      apps/explorer/lib/explorer/chain/smart_contract.ex
  9. 89
      apps/explorer/lib/explorer/smart_contract/eth_bytecode_db_interface.ex
  10. 18
      apps/explorer/lib/explorer/smart_contract/rust_verifier_interface_behaviour.ex
  11. 21
      apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex
  12. 6
      apps/explorer/lib/explorer/smart_contract/vyper/publisher.ex
  13. 9
      apps/explorer/priv/repo/migrations/20240325195446_add_verified_via_verifier_alliance.exs
  14. 3
      apps/explorer/test/support/factory.ex

@ -66,7 +66,7 @@ defmodule BlockScoutWeb.API.V2.ImportController do
| {:not_found, {:error, :not_found}}
| {:sensitive_endpoints_api_key, any()}
| Plug.Conn.t()
def try_to_search_contract(conn, %{"address_hash_param" => address_hash_string}) do
def try_to_search_contract(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:sensitive_endpoints_api_key, api_key} when not is_nil(api_key) <-
{:sensitive_endpoints_api_key, Application.get_env(:block_scout_web, :sensitive_endpoints_api_key)},
{:api_key, ^api_key} <- {:api_key, get_api_key_header(conn)},
@ -79,7 +79,10 @@ defmodule BlockScoutWeb.API.V2.ImportController do
with {:ok, %{"sourceType" => type} = source} <-
%{}
|> prepare_bytecode_for_microservice(creation_tx_input, Data.to_string(address.contract_code))
|> EthBytecodeDBInterface.search_contract_in_eth_bytecode_internal_db(),
|> EthBytecodeDBInterface.search_contract_in_eth_bytecode_internal_db(
address_hash_string,
params_to_contract_search_options(params)
),
{:ok, _} <- LookUpSmartContractSourcesOnDemand.process_contract_source(type, source, address.hash) do
conn
|> put_view(ApiView)
@ -93,6 +96,16 @@ defmodule BlockScoutWeb.API.V2.ImportController do
end
end
defp params_to_contract_search_options(%{"import_from" => "verifier_alliance"}) do
[only_verifier_alliance?: true]
end
defp params_to_contract_search_options(%{"import_from" => "eth_bytecode_db"}) do
[only_eth_bytecode_db?: true]
end
defp params_to_contract_search_options(_), do: []
defp valid_url?(url) when is_binary(url) do
uri = URI.parse(url)
uri.scheme != nil && uri.host =~ "."

@ -168,6 +168,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
"is_fully_verified" => fully_verified,
"is_verified_via_sourcify" => address.smart_contract.verified_via_sourcify && smart_contract_verified,
"is_verified_via_eth_bytecode_db" => address.smart_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => address.smart_contract.verified_via_verifier_alliance,
"is_vyper_contract" => target_contract.is_vyper_contract,
"minimal_proxy_address_hash" =>
minimal_proxy_template && Address.checksum(metadata_for_verification.address_hash),

@ -112,6 +112,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029",
"abi" => target_contract.abi,
"is_verified_via_eth_bytecode_db" => target_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => target_contract.verified_via_verifier_alliance,
"language" => smart_contract_language(target_contract),
"license_type" => "none"
}
@ -205,6 +206,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029",
"abi" => target_contract.abi,
"is_verified_via_eth_bytecode_db" => target_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => target_contract.verified_via_verifier_alliance,
"language" => smart_contract_language(target_contract),
"license_type" => "gnu_agpl_v3"
}
@ -300,6 +302,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029",
"abi" => target_contract.abi,
"is_verified_via_eth_bytecode_db" => target_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => target_contract.verified_via_verifier_alliance,
"language" => smart_contract_language(target_contract),
"license_type" => "none"
}
@ -411,6 +414,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"creation_bytecode" => proxy_tx_input,
"abi" => implementation_contract.abi,
"is_verified_via_eth_bytecode_db" => implementation_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => implementation_contract.verified_via_verifier_alliance,
"language" => smart_contract_language(implementation_contract),
"license_type" => "bsd_3_clause"
}
@ -825,6 +829,337 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
GenServer.stop(pid)
end
test "automatically verify contract using search-all (allianceSources) endpoint", %{conn: conn} do
{:ok, pid} = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand.start_link([])
old_chain_id = Application.get_env(:block_scout_web, :chain_id)
Application.put_env(:block_scout_web, :chain_id, 5)
bypass = Bypass.open()
eth_bytecode_response =
File.read!("./test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_response.json")
old_env = Application.get_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour,
service_url: "http://localhost:#{bypass.port}",
enabled: true,
type: "eth_bytecode_db",
eth_bytecode_db?: true
)
address = insert(:contract_address)
insert(:transaction,
created_contract_address_hash: address.hash,
input:
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
)
|> with_block()
topic = "addresses:#{address.hash}"
{:ok, _reply, _socket} =
BlockScoutWeb.UserSocketV2
|> socket("no_id", %{})
|> subscribe_and_join(topic)
Bypass.expect_once(bypass, "POST", "/api/v2/bytecodes/sources_search_all", fn conn ->
Conn.resp(conn, 200, eth_bytecode_response)
end)
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "eth_bytecode_db_lookup_started",
topic: ^topic
},
:timer.seconds(1)
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "smart_contract_was_verified",
topic: ^topic
},
:timer.seconds(1)
response = json_response(request, 200)
assert response ==
%{
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
}
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert response = json_response(request, 200)
assert %{"is_verified" => true} = response
assert %{"is_verified_via_eth_bytecode_db" => true} = response
assert %{"is_partially_verified" => true} = response
assert %{"is_verified_via_sourcify" => false} = response
assert %{"is_verified_via_verifier_alliance" => true} = response
assert %{"is_fully_verified" => false} = response
smart_contract = Jason.decode!(eth_bytecode_response)["allianceSources"] |> List.first()
assert response["compiler_settings"] == Jason.decode!(smart_contract["compilerSettings"])
assert response["name"] == smart_contract["contractName"]
assert response["compiler_version"] == smart_contract["compilerVersion"]
assert response["file_path"] == smart_contract["fileName"]
assert response["constructor_args"] == smart_contract["constructorArguments"]
assert response["abi"] == Jason.decode!(smart_contract["abi"])
assert response["source_code"] == smart_contract["sourceFiles"][smart_contract["fileName"]]
assert response["external_libraries"] == [
%{
"address_hash" => "0x00000000D41867734BBee4C6863D9255b2b06aC1",
"name" => "__CACHE_BREAKER__"
}
]
additional_sources =
for file_name <- Map.keys(smart_contract["sourceFiles"]), smart_contract["fileName"] != file_name do
%{
"source_code" => smart_contract["sourceFiles"][file_name],
"file_path" => file_name
}
end
assert response["additional_sources"] |> Enum.sort_by(fn x -> x["file_path"] end) ==
additional_sources |> Enum.sort_by(fn x -> x["file_path"] end)
Application.put_env(:block_scout_web, :chain_id, old_chain_id)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, old_env)
Bypass.down(bypass)
GenServer.stop(pid)
end
test "automatically verify contract using search-all (prefer sourcify FULL match) endpoint", %{conn: conn} do
{:ok, pid} = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand.start_link([])
old_chain_id = Application.get_env(:block_scout_web, :chain_id)
Application.put_env(:block_scout_web, :chain_id, 5)
bypass = Bypass.open()
eth_bytecode_response =
File.read!(
"./test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_partial_response.json"
)
old_env = Application.get_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour,
service_url: "http://localhost:#{bypass.port}",
enabled: true,
type: "eth_bytecode_db",
eth_bytecode_db?: true
)
address = insert(:contract_address)
insert(:transaction,
created_contract_address_hash: address.hash,
input:
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
)
|> with_block()
topic = "addresses:#{address.hash}"
{:ok, _reply, _socket} =
BlockScoutWeb.UserSocketV2
|> socket("no_id", %{})
|> subscribe_and_join(topic)
Bypass.expect_once(bypass, "POST", "/api/v2/bytecodes/sources_search_all", fn conn ->
Conn.resp(conn, 200, eth_bytecode_response)
end)
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "eth_bytecode_db_lookup_started",
topic: ^topic
},
:timer.seconds(1)
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "smart_contract_was_verified",
topic: ^topic
},
:timer.seconds(1)
response = json_response(request, 200)
assert response ==
%{
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
}
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert response = json_response(request, 200)
assert %{"is_verified" => true} = response
assert %{"is_verified_via_eth_bytecode_db" => true} = response
assert %{"is_partially_verified" => false} = response
assert %{"is_verified_via_sourcify" => true} = response
assert %{"is_verified_via_verifier_alliance" => false} = response
assert %{"is_fully_verified" => true} = response
smart_contract = Jason.decode!(eth_bytecode_response)["sourcifySources"] |> List.first()
assert response["compiler_settings"] == Jason.decode!(smart_contract["compilerSettings"])
assert response["name"] == smart_contract["contractName"]
assert response["compiler_version"] == smart_contract["compilerVersion"]
assert response["file_path"] == smart_contract["fileName"]
assert response["constructor_args"] == smart_contract["constructorArguments"]
assert response["abi"] == Jason.decode!(smart_contract["abi"])
assert response["source_code"] == smart_contract["sourceFiles"][smart_contract["fileName"]]
assert response["external_libraries"] == [
%{
"address_hash" => "0x00000000D41867734BBee4C6863D9255b2b06aC1",
"name" => "__CACHE_BREAKER__"
}
]
additional_sources =
for file_name <- Map.keys(smart_contract["sourceFiles"]), smart_contract["fileName"] != file_name do
%{
"source_code" => smart_contract["sourceFiles"][file_name],
"file_path" => file_name
}
end
assert response["additional_sources"] |> Enum.sort_by(fn x -> x["file_path"] end) ==
additional_sources |> Enum.sort_by(fn x -> x["file_path"] end)
Application.put_env(:block_scout_web, :chain_id, old_chain_id)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, old_env)
Bypass.down(bypass)
GenServer.stop(pid)
end
test "automatically verify contract using search-all (take eth bytecode db FULL match) endpoint", %{conn: conn} do
{:ok, pid} = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand.start_link([])
old_chain_id = Application.get_env(:block_scout_web, :chain_id)
Application.put_env(:block_scout_web, :chain_id, 5)
bypass = Bypass.open()
eth_bytecode_response =
File.read!(
"./test/support/fixture/smart_contract/eth_bytecode_db_search_all_alliance_sources_partial_response_eth_bdb_full.json"
)
old_env = Application.get_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour,
service_url: "http://localhost:#{bypass.port}",
enabled: true,
type: "eth_bytecode_db",
eth_bytecode_db?: true
)
address = insert(:contract_address)
insert(:transaction,
created_contract_address_hash: address.hash,
input:
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
)
|> with_block()
topic = "addresses:#{address.hash}"
{:ok, _reply, _socket} =
BlockScoutWeb.UserSocketV2
|> socket("no_id", %{})
|> subscribe_and_join(topic)
Bypass.expect_once(bypass, "POST", "/api/v2/bytecodes/sources_search_all", fn conn ->
Conn.resp(conn, 200, eth_bytecode_response)
end)
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "eth_bytecode_db_lookup_started",
topic: ^topic
},
:timer.seconds(1)
assert_receive %Phoenix.Socket.Message{
payload: %{},
event: "smart_contract_was_verified",
topic: ^topic
},
:timer.seconds(1)
response = json_response(request, 200)
assert response ==
%{
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
}
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert response = json_response(request, 200)
assert %{"is_verified" => true} = response
assert %{"is_verified_via_eth_bytecode_db" => true} = response
assert %{"is_partially_verified" => false} = response
assert %{"is_verified_via_sourcify" => false} = response
assert %{"is_verified_via_verifier_alliance" => false} = response
assert %{"is_fully_verified" => true} = response
smart_contract = Jason.decode!(eth_bytecode_response)["ethBytecodeDbSources"] |> List.first()
assert response["compiler_settings"] == Jason.decode!(smart_contract["compilerSettings"])
assert response["name"] == smart_contract["contractName"]
assert response["compiler_version"] == smart_contract["compilerVersion"]
assert response["file_path"] == smart_contract["fileName"]
assert response["constructor_args"] == smart_contract["constructorArguments"]
assert response["abi"] == Jason.decode!(smart_contract["abi"])
assert response["source_code"] == smart_contract["sourceFiles"][smart_contract["fileName"]]
assert response["external_libraries"] == [
%{
"address_hash" => "0x00000000D41867734BBee4C6863D9255b2b06aC1",
"name" => "__CACHE_BREAKER__"
}
]
additional_sources =
for file_name <- Map.keys(smart_contract["sourceFiles"]), smart_contract["fileName"] != file_name do
%{
"source_code" => smart_contract["sourceFiles"][file_name],
"file_path" => file_name
}
end
assert response["additional_sources"] |> Enum.sort_by(fn x -> x["file_path"] end) ==
additional_sources |> Enum.sort_by(fn x -> x["file_path"] end)
Application.put_env(:block_scout_web, :chain_id, old_chain_id)
Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, old_env)
Bypass.down(bypass)
GenServer.stop(pid)
end
test "check fetch interval for LookUpSmartContractSourcesOnDemand and use sources:search endpoint since chain_id is unset",
%{conn: conn} do
{:ok, pid} = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand.start_link([])

@ -0,0 +1,43 @@
{
"ethBytecodeDbSources": [
{
"fileName": "Test_eth.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"Test.sol\":{}},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":199},\"outputSelection\":{\"*\":{\"\":[\"ast\"],\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_eth.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "FULL"
}
],
"sourcifySources": [{
"fileName": "Test.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "FULL"
}],
"allianceSources": [{
"fileName": "Test_1.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_1.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}]
}

@ -0,0 +1,43 @@
{
"ethBytecodeDbSources": [
{
"fileName": "Test_eth.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_eth.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "FULL"
}
],
"sourcifySources": [{
"fileName": "Test.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}],
"allianceSources": [{
"fileName": "Test_1.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_1.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}]
}

@ -0,0 +1,43 @@
{
"ethBytecodeDbSources": [
{
"fileName": "Test_eth.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"Test.sol\":{}},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":199},\"outputSelection\":{\"*\":{\"\":[\"ast\"],\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_eth.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}
],
"sourcifySources": [{
"fileName": "Test.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"Test.sol\":{}},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":199},\"outputSelection\":{\"*\":{\"\":[\"ast\"],\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}],
"allianceSources": [{
"fileName": "Test_1.sol",
"contractName": "Test",
"compilerVersion": "v0.8.17+commit.8df45f5f",
"compilerSettings": "{\"libraries\":{\"\":{\"__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"}},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test_1.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",
"matchType": "PARTIAL"
}]
}

@ -7,7 +7,7 @@
"compilerSettings": "{\"libraries\":{\"Test.sol\":{}},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":199},\"outputSelection\":{\"*\":{\"\":[\"ast\"],\"*\":[\"abi\",\"evm.bytecode\",\"evm.deployedBytecode\",\"evm.methodIdentifiers\"]}}}",
"sourceType": "SOLIDITY",
"sourceFiles": {
"Test.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
"Test_eth.sol": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.17;\r\n\r\ncontract Test {\r\n enum E {\r\n V1, V2, V3, V4\r\n }\r\n struct A {\r\n E a;\r\n uint256[] b;\r\n B[] c;\r\n }\r\n\r\n struct B {\r\n uint256 d;\r\n uint256 e;\r\n }\r\n\r\n function get(uint256 x) external pure returns (A memory) {\r\n uint256[] memory b = new uint256[](3);\r\n b[0] = 1;\r\n b[1] = 2;\r\n b[2] = 3;\r\n B[] memory c = new B[](3);\r\n c[0] = B(1, 2);\r\n c[1] = B(3, 4);\r\n c[2] = B(5, 6);\r\n return A(E.V3, b, c);\r\n }\r\n}"
},
"abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"components\":[{\"type\":\"uint8\"},{\"type\":\"uint256[]\"},{\"components\":[{\"type\":\"uint256\"},{\"type\":\"uint256\"}],\"type\":\"tuple[]\"}],\"internalType\":\"struct Test.A\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
"constructorArguments": "0x0000000000000000000000003e5c63644e683549055b9be8653de26e0b4cd36e",

@ -263,6 +263,8 @@ defmodule Explorer.Chain.SmartContract do
* `abi` - The [JSON ABI specification](https://solidity.readthedocs.io/en/develop/abi-spec.html#json) for this
contract.
* `verified_via_sourcify` - whether contract verified through Sourcify utility or not.
* `verified_via_eth_bytecode_db` - whether contract automatically verified via eth-bytecode-db or not.
* `verified_via_verifier_alliance` - whether contract automatically verified via Verifier Alliance or not.
* `partially_verified` - whether contract verified using partial matched source code or not.
* `is_vyper_contract` - boolean flag, determines if contract is Vyper or not
* `file_path` - show the filename or path to the file of the contract source file
@ -275,7 +277,6 @@ defmodule Explorer.Chain.SmartContract do
* `implementation_address_hash` - address hash of the proxy's implementation if any
* `autodetect_constructor_args` - field was added for storing user's choice
* `is_yul` - field was added for storing user's choice
* `verified_via_eth_bytecode_db` - whether contract automatically verified via eth-bytecode-db or not.
"""
typed_schema "smart_contracts" do
field(:name, :string, null: false)
@ -288,6 +289,8 @@ defmodule Explorer.Chain.SmartContract do
embeds_many(:external_libraries, ExternalLibrary, on_replace: :delete)
field(:abi, {:array, :map})
field(:verified_via_sourcify, :boolean)
field(:verified_via_eth_bytecode_db, :boolean)
field(:verified_via_verifier_alliance, :boolean)
field(:partially_verified, :boolean)
field(:file_path, :string)
field(:is_vyper_contract, :boolean)
@ -301,7 +304,6 @@ defmodule Explorer.Chain.SmartContract do
field(:autodetect_constructor_args, :boolean, virtual: true)
field(:is_yul, :boolean, virtual: true)
field(:metadata_from_verified_twin, :boolean, virtual: true)
field(:verified_via_eth_bytecode_db, :boolean)
field(:license_type, Ecto.Enum, values: @license_enum, default: :none)
has_many(
@ -344,6 +346,8 @@ defmodule Explorer.Chain.SmartContract do
:evm_version,
:optimization_runs,
:verified_via_sourcify,
:verified_via_eth_bytecode_db,
:verified_via_verifier_alliance,
:partially_verified,
:file_path,
:is_vyper_contract,
@ -354,7 +358,6 @@ defmodule Explorer.Chain.SmartContract do
:compiler_settings,
:implementation_address_hash,
:implementation_fetched_at,
:verified_via_eth_bytecode_db,
:license_type
])
|> validate_required([
@ -388,6 +391,8 @@ defmodule Explorer.Chain.SmartContract do
:optimization_runs,
:constructor_arguments,
:verified_via_sourcify,
:verified_via_eth_bytecode_db,
:verified_via_verifier_alliance,
:partially_verified,
:file_path,
:is_vyper_contract,
@ -396,7 +401,6 @@ defmodule Explorer.Chain.SmartContract do
:contract_code_md5,
:implementation_name,
:autodetect_constructor_args,
:verified_via_eth_bytecode_db,
:license_type
])
|> (&if(verification_with_files?,

@ -10,10 +10,11 @@ defmodule Explorer.SmartContract.EthBytecodeDBInterface do
Map.merge(body, %{
"chain" => to_string(chain_id),
"address" => to_string(address_hash)
})
}),
false
)
else
http_post_request(bytecode_search_sources_url(), body)
http_post_request(bytecode_search_sources_url(), body, false)
end
end
@ -21,28 +22,85 @@ defmodule Explorer.SmartContract.EthBytecodeDBInterface do
Function to search smart contracts in eth-bytecode-db, similar to `search_contract/2` but
this function uses only `/api/v2/bytecodes/sources:search` method
"""
@spec search_contract_in_eth_bytecode_internal_db(map()) :: {:error, any} | {:ok, any}
def search_contract_in_eth_bytecode_internal_db(%{"bytecode" => _, "bytecodeType" => _} = body) do
http_post_request(bytecode_search_sources_url(), body)
@spec search_contract_in_eth_bytecode_internal_db(map(), binary(), keyword()) :: {:error, any} | {:ok, any}
def search_contract_in_eth_bytecode_internal_db(
%{"bytecode" => _, "bytecodeType" => _} = body,
address_hash_string,
options
) do
chain_id = Application.get_env(:block_scout_web, :chain_id)
{url, body} =
cond do
Keyword.get(options, :only_verifier_alliance?, false) ->
{bytecode_search_alliance_sources_url(),
%{
"chain" => to_string(chain_id),
"address" => address_hash_string
}}
Keyword.get(options, :only_eth_bytecode_db?, false) ->
{bytecode_search_sources_url(), body}
true ->
{bytecode_search_all_sources_url(),
Map.merge(body, %{
"chain" => to_string(chain_id),
"address" => address_hash_string,
"onlyLocal" => true
})}
end
http_post_request(url, body, false, options)
end
def process_verifier_response(%{"sourcifySources" => [src | _]}) do
def process_verifier_response(
%{
"allianceSources" => [%{"matchType" => "PARTIAL"} | _],
"ethBytecodeDbSources" => _,
"sourcifySources" => [%{"matchType" => "FULL"} = src | _]
},
_
) do
{:ok, Map.put(src, "sourcify?", true)}
end
def process_verifier_response(%{"ethBytecodeDbSources" => [src | _]}) do
def process_verifier_response(
%{
"allianceSources" => [%{"matchType" => "PARTIAL"} | _],
"ethBytecodeDbSources" => [%{"matchType" => "FULL"} = src | _],
"sourcifySources" => _
},
_
) do
{:ok, src}
end
def process_verifier_response(%{"ethBytecodeDbSources" => [], "sourcifySources" => []}) do
{:error, :no_matched_sources}
def process_verifier_response(%{"allianceSources" => [src | _]}, _) do
{:ok, Map.put(src, "verifier_alliance?", true)}
end
def process_verifier_response(%{"sources" => [src | _]}) do
def process_verifier_response(%{"sourcifySources" => [src | _]}, _) do
{:ok, Map.put(src, "sourcify?", true)}
end
def process_verifier_response(%{"ethBytecodeDbSources" => [src | _]}, _) do
{:ok, src}
end
def process_verifier_response(%{"sources" => []}) do
def process_verifier_response(%{"ethBytecodeDbSources" => [], "sourcifySources" => [], "allianceSources" => []}, _) do
{:error, :no_matched_sources}
end
def process_verifier_response(%{"sources" => [src | _]}, options) do
if Keyword.get(options, :only_verifier_alliance?, false) do
{:ok, Map.put(src, "verifier_alliance?", true)}
else
{:ok, src}
end
end
def process_verifier_response(%{"sources" => []}, _) do
{:ok, nil}
end
@ -64,5 +122,14 @@ defmodule Explorer.SmartContract.EthBytecodeDBInterface do
end
end
def bytecode_search_alliance_sources_url do
# workaround because of https://github.com/PSPDFKit-labs/bypass/issues/122
if Mix.env() == :test do
"#{base_api_url()}" <> "/bytecodes/sources_search_alliance"
else
"#{base_api_url()}" <> "/bytecodes/sources:search-alliance"
end
end
use Explorer.SmartContract.RustVerifierInterfaceBehaviour
end

@ -63,14 +63,14 @@ defmodule Explorer.SmartContract.RustVerifierInterfaceBehaviour do
http_post_request(vyper_standard_json_verification_url(), append_metadata(body, metadata), true)
end
def http_post_request(url, body, is_verification_request? \\ false) do
def http_post_request(url, body, is_verification_request?, options \\ []) do
headers = [{"Content-Type", "application/json"}]
case HTTPoison.post(url, Jason.encode!(body), maybe_put_api_key_header(headers, is_verification_request?),
recv_timeout: @post_timeout
) do
{:ok, %Response{body: body, status_code: _}} ->
process_verifier_response(body)
process_verifier_response(body, options)
{:error, error} ->
old_truncate = Application.get_env(:logger, :truncate)
@ -103,7 +103,7 @@ defmodule Explorer.SmartContract.RustVerifierInterfaceBehaviour do
def http_get_request(url) do
case HTTPoison.get(url) do
{:ok, %Response{body: body, status_code: 200}} ->
process_verifier_response(body)
process_verifier_response(body, [])
{:ok, %Response{body: body, status_code: _}} ->
{:error, body}
@ -132,27 +132,27 @@ defmodule Explorer.SmartContract.RustVerifierInterfaceBehaviour do
http_get_request(vyper_versions_list_url())
end
def process_verifier_response(body) when is_binary(body) do
def process_verifier_response(body, options) when is_binary(body) do
case Jason.decode(body) do
{:ok, decoded} ->
process_verifier_response(decoded)
process_verifier_response(decoded, options)
_ ->
{:error, body}
end
end
def process_verifier_response(%{"status" => "SUCCESS", "source" => source}) do
def process_verifier_response(%{"status" => "SUCCESS", "source" => source}, _) do
{:ok, source}
end
def process_verifier_response(%{"status" => "FAILURE", "message" => error}) do
def process_verifier_response(%{"status" => "FAILURE", "message" => error}, _) do
{:error, error}
end
def process_verifier_response(%{"compilerVersions" => versions}), do: {:ok, versions}
def process_verifier_response(%{"compilerVersions" => versions}, _), do: {:ok, versions}
def process_verifier_response(other), do: {:error, other}
def process_verifier_response(other, _), do: {:error, other}
def solidity_multiple_files_verification_url,
do: "#{base_api_url()}" <> "/verifier/solidity/sources:verify-multi-part"

@ -176,8 +176,9 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
|> Map.put("secondary_sources", secondary_sources)
|> Map.put("compiler_settings", if(is_standard_json?, do: compiler_settings))
|> Map.put("partially_verified", match_type == "PARTIAL")
|> Map.put("verified_via_eth_bytecode_db", automatically_verified?)
|> Map.put("verified_via_sourcify", source["sourcify?"])
|> Map.put("verified_via_eth_bytecode_db", automatically_verified?)
|> Map.put("verified_via_verifier_alliance", source["verifier_alliance?"])
|> Map.put("license_type", initial_params["license_type"])
publish_smart_contract(address_hash, prepared_params, Jason.decode!(abi_string || "null"))
@ -236,12 +237,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
constructor_arguments = params["constructor_arguments"]
compiler_settings = params["compiler_settings"]
clean_constructor_arguments =
if constructor_arguments != nil && constructor_arguments != "" do
constructor_arguments
else
nil
end
clean_constructor_arguments = clear_constructor_arguments(constructor_arguments)
clean_compiler_settings =
if compiler_settings in ["", nil, %{}] do
@ -268,16 +264,25 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
secondary_sources: params["secondary_sources"],
abi: abi,
verified_via_sourcify: params["verified_via_sourcify"] || false,
verified_via_eth_bytecode_db: params["verified_via_eth_bytecode_db"] || false,
verified_via_verifier_alliance: params["verified_via_verifier_alliance"] || false,
partially_verified: params["partially_verified"] || false,
is_vyper_contract: false,
autodetect_constructor_args: params["autodetect_constructor_args"],
is_yul: params["is_yul"] || false,
compiler_settings: clean_compiler_settings,
verified_via_eth_bytecode_db: params["verified_via_eth_bytecode_db"] || false,
license_type: prepare_license_type(params["license_type"]) || :none
}
end
defp clear_constructor_arguments(constructor_arguments) do
if constructor_arguments != nil && constructor_arguments != "" do
constructor_arguments
else
nil
end
end
defp prepare_external_libraries(nil), do: []
defp prepare_external_libraries(map) do

@ -83,7 +83,7 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
"sourceFiles" => sources,
"compilerSettings" => compiler_settings_string,
"matchType" => match_type
},
} = source,
address_hash,
initial_params,
save_file_path?,
@ -111,6 +111,7 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
|> Map.put("evm_version", compiler_settings["evmVersion"])
|> Map.put("partially_verified", match_type == "PARTIAL")
|> Map.put("verified_via_eth_bytecode_db", automatically_verified?)
|> Map.put("verified_via_verifier_alliance", source["verifier_alliance?"])
|> Map.put(
"optimization",
if(is_nil(compiler_settings["optimize"]), do: true, else: compiler_settings["optimize"])
@ -180,10 +181,11 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
secondary_sources: params["secondary_sources"],
abi: abi,
verified_via_sourcify: false,
verified_via_eth_bytecode_db: params["verified_via_eth_bytecode_db"] || false,
verified_via_verifier_alliance: params["verified_via_verifier_alliance"] || false,
partially_verified: params["partially_verified"] || false,
is_vyper_contract: true,
file_path: params["file_path"],
verified_via_eth_bytecode_db: params["verified_via_eth_bytecode_db"] || false,
compiler_settings: clean_compiler_settings,
license_type: prepare_license_type(params["license_type"]) || :none
}

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Migrations.AddVerifiedViaVerifierAlliance do
use Ecto.Migration
def change do
alter table(:smart_contracts) do
add(:verified_via_verifier_alliance, :boolean, null: true)
end
end
end

@ -885,7 +885,8 @@ defmodule Explorer.Factory do
contract_code_md5: bytecode_md5,
verified_via_sourcify: Enum.random([true, false]),
is_vyper_contract: Enum.random([true, false]),
verified_via_eth_bytecode_db: Enum.random([true, false])
verified_via_eth_bytecode_db: Enum.random([true, false]),
verified_via_verifier_alliance: Enum.random([true, false])
}
end

Loading…
Cancel
Save